簡介
JVM的參數有很多很多,根據我的統計JDK8中JVM的參數總共有1853個,正式的參數也有680個。
這么多參數帶給我們的是對JVM的細粒度的控制,但是並不是所有的參數都需要我們自己去調節的,我們需要關注的是一些最常用的,對性能影響比較大的GC參數即可。
為了更好的讓大家理解JDK8中 GC的調優的秘籍,這里特意准備了八張圖。在本文的最后,還附帶了一個總結的PDF all in one文檔,大家把PDF下載回去,遇到問題就看兩眼,不美嗎?
分代垃圾回收器的內存結構
為了更好的提升GC的效率,現代的JVM都是采用的分代垃圾回收的策略(ZGC不是)。
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方式:
其中對於ParallelGC和CMS GC又可以對年輕代和老年代分別設置GC方式。
大家看到上圖可能有一個疑問,Parallel scavenge和Parallel有什么區別呢?
其實這兩個GC的算法是類似的,Parallel Scavenge收集器也經常稱為“吞吐量優先”收集器,Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量; -XX:MaxGCPauseMillis:控制最大垃圾收集停頓時間; -XX:GCTimeRatio:設置吞吐量大小。
同時Parallel Scavenge收集器能夠配合自適應調節策略,把內存管理的調優任務交給虛擬機去完成。
JDK8中默認開啟的是ParallelGC。
打印GC信息
如果想研究和理解GC的內部信息,GC信息打印是少不了的:
上圖提供了一些非常有用的GC日志的控制參數。
內存調整參數
JVM分為Heap區和非Heap區,各個區又有更細的划分,下面就是調整各個區域大小的參數:
Thread配置
TLAB大家還記得嗎?TLAB的全稱是Thread-Local Allocation Buffers。TLAB是在Eden區間分配的一個一個的連續空間。然后將這些連續的空間分配個各個線程使用。
因為每一個線程都有自己的獨立空間,所以這里不涉及到同步的概念。
上圖就是TLAB的參數。
通用GC參數
雖然JDK8的GC這么多,但是他們有一些通用的GC參數:
這里講解一下Young space tenuring,怎么翻譯我不是很清楚,這個主要就是指Young space中的對象經過多少次GC之后會被提升到Old space中。
CMS GC
CMS全稱是Concurrent mark sweep。是一個非常非常復雜的GC。
復雜到什么程度呢?光光是CMS調優的參數都有一百多個!
下圖是常用的CMS的參數。
CMS這里就不多講了,因為在JDK9之后,CMS就已經被廢棄了。
主要原因是CMS太過復雜,如果要向下兼容需要巨大的工作量,然后就直接被廢棄了。
在JDK9之后,默認的GC是G1。
G1參數
G1收集器是分代的和region化的,也就是整個堆內存被分為一系列大小相等的region。在啟動時,JVM設置region的大小,根據堆大小的不同,region的大小可以在1MB到32MB之間變動,region的數量最多不超過2048個。Eden區、Survivor區、老年代是這些region的邏輯集合,它們並不是連續的。
G1中的垃圾收集過程:年輕代收集和混合收集交替進行,背后有全局的並發標記周期在進行。當老年代分區占用的空間達到或超過初始閾值,就會觸發並發標記周期。
下圖是G1的調優參數:
總結
上面總共8副圖,我把他們做成了一個PDF,預覽界面大概是這樣子的:
大家可以通過下面的鏈接直接下載PDF版本:
如果遇到問題可以直接拿過來參考。這種東西英文名字應該叫JDK8 GC cheatsheet,翻譯成中文應該就是JDK8 GC調優秘籍!
本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/jdk8-gc-cheatsheet/
本文來源:flydean的博客
歡迎關注我的公眾號:程序那些事,更多精彩等着您!