1. 程式人生 > >八張圖徹底瞭解JDK8 GC調優祕籍-附PDF下載

八張圖徹底瞭解JDK8 GC調優祕籍-附PDF下載

[toc] # 簡介 JVM的引數有很多很多,根據我的統計JDK8中JVM的引數總共有1853個,正式的引數也有680個。 這麼多引數帶給我們的是對JVM的細粒度的控制,但是並不是所有的引數都需要我們自己去調節的,我們需要關注的是一些最常用的,對效能影響比較大的GC引數即可。 為了更好的讓大家理解JDK8中 GC的調優的祕籍,這裡特意準備了八張圖。在本文的最後,還附帶了一個總結的PDF all in one文件,大家把PDF下載回去,遇到問題就看兩眼,不美嗎? # 分代垃圾回收器的記憶體結構 為了更好的提升GC的效率,現代的JVM都是採用的分代垃圾回收的策略(ZGC不是)。 ![](https://img-blog.csdnimg.cn/20200622111543500.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) java執行時記憶體可以分為JVM記憶體和非JVM記憶體。 JVM記憶體又可以分為堆記憶體和非堆記憶體。 堆記憶體大家都很熟悉了,YoungGen中的Eden,Survivor和OldGen。 非堆記憶體中儲存的有thread Stack,Code Cache, NIO Direct Buffers,Metaspace等。 注意這裡的Metaspace元空間是方法區在JDK8的實現,它是在本地記憶體中分配的。 # JDK8中可用的GC JDK8中到底有哪些可以使用的GC呢? 這裡我們以HotSpot JVM為例,總共可以使用4大GC方式: ![](https://img-blog.csdnimg.cn/20200622112250706.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 其中對於ParallelGC和CMS GC又可以對年輕代和老年代分別設定GC方式。 大家看到上圖可能有一個疑問,Parallel scavenge和Parallel有什麼區別呢? 其實這兩個GC的演算法是類似的,Parallel Scavenge收集器也經常稱為“吞吐量優先”收集器,Parallel Scavenge收集器提供了兩個引數用於精確控制吞吐量; -XX:MaxGCPauseMillis:控制最大垃圾收集停頓時間; -XX:GCTimeRatio:設定吞吐量大小。 同時Parallel Scavenge收集器能夠配合自適應調節策略,把記憶體管理的調優任務交給虛擬機器去完成。 > JDK8中預設開啟的是ParallelGC。 # 列印GC資訊 如果想研究和理解GC的內部資訊,GC資訊列印是少不了的: ![](https://img-blog.csdnimg.cn/20200622113051176.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 上圖提供了一些非常有用的GC日誌的控制引數。 # 記憶體調整引數 JVM分為Heap區和非Heap區,各個區又有更細的劃分,下面就是調整各個區域大小的引數: ![](https://img-blog.csdnimg.cn/20200622113221955.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) # Thread配置 TLAB大家還記得嗎? 如果一個物件的分配是在方法內部,並且沒有多執行緒訪問的情況下,那麼這個物件其實可以看做是一個本地物件,這樣的物件不管建立在哪裡都只對本執行緒中的本方法可見,因此可以直接分配在棧空間中。 棧上分配的物件因為不用考慮同步,所以執行速度肯定會更加快速,這也是為什麼JVM會引入棧上分配的原因。 ![](https://img-blog.csdnimg.cn/2020062212135387.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 上圖就是TLAB的引數。 # 通用GC引數 雖然JDK8的GC這麼多,但是他們有一些通用的GC引數: ![](https://img-blog.csdnimg.cn/20200622121616181.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 這裡講解一下Young space tenuring,怎麼翻譯我不是很清楚,這個主要就是指Young space中的物件經過多少次GC之後會被提升到Old space中。 # CMS GC CMS全稱是Concurrent mark sweep。是一個非常非常複雜的GC。 複雜到什麼程度呢?光光是CMS調優的引數都有一百多個! 下圖是常用的CMS的引數。 ![](https://img-blog.csdnimg.cn/20200622121812439.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) CMS這裡就不多講了,因為在JDK9之後,CMS就已經被廢棄了。 主要原因是CMS太過複雜,如果要向下相容需要巨大的工作量,然後就直接被廢棄了。 在JDK9之後,預設的GC是G1。 # G1引數 G1收集器是分代的和region化的,也就是整個堆記憶體被分為一系列大小相等的region。在啟動時,JVM設定region的大小,根據堆大小的不同,region的大小可以在1MB到32MB之間變動,region的數量最多不超過2048個。Eden區、Survivor區、老年代是這些region的邏輯集合,它們並不是連續的。 G1中的垃圾收集過程:年輕代收集和混合收集交替進行,背後有全域性的併發標記週期在進行。當老年代分割槽佔用的空間達到或超過初始閾值,就會觸發併發標記週期。 下圖是G1的調優引數: ![](https://img-blog.csdnimg.cn/20200622122155457.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) # 總結 上面總共8副圖,我把他們做成了一個PDF,預覽介面大概是這樣子的: ![](https://img-blog.csdnimg.cn/20200622122548169.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 大家可以通過下面的連結直接下載PDF版本: [JDK8GC-cheatsheet.pdf](https://github.com/ddean2009/www.flydean.com/blob/master/cheatSheet/JDK8GC-cheatsheet.pdf) 如果遇到問題可以直接拿過來參考。這種東西英文名字應該叫JDK8 GC cheatsheet,翻譯成中文應該就是JDK8 GC調優祕籍! > 本文作者:flydean程式那些事 > > 本文連結:[http://www.flydean.com/jdk8-gc-cheatsheet/](http://www.flydean.com/jdk8-gc-cheatsheet/) > > 本文來源:flydean的部落格 > > 歡迎關注我的公眾號:程式那些事,更多精彩等著您!