JVM GC調優入門
這篇文章會介紹幾個常用的調優參數,再通過兩個案例介紹如何進行JVM GC調優。閱讀這篇文章的前提是假設大家已經對JVM內存模型、JVM的垃圾回收算法、JVM的垃圾回收器都比較熟悉了。
JVM調優是必須的嗎?
閱讀下面的內容之前首先拋出這個問題:GC調優對于java服務是必須的嗎?實際上,我感覺80%的java的程序員在實際工作中都沒有碰到過GC調優吧,這是因為多數的Java應用不需要在服務器上進行GC優化,多數導致GC問題的Java應用,都不是因為我們參數設置錯誤,而是代碼問題,需要記住一點:GC調優是最后要做的工作。
GC調優的目的可以總結為下面兩點:
- 減少對象晉升到老年代的數量
- 減少FullGC的執行時間
減少對象晉升到老年代的數量
分代垃圾回收是Oracle JVM中回收思想。 我們知道在Eden區創建的對象,在from Survivor 復制到to Survivor區之后,達到一定年齡就進入了老年代。有些對象因為比較大就直接進入了老年代。在老年代的GC時間相比于年輕代時間更長。因此,減少對象進入老年代可以降低Full GC的頻率
減少FullGC的執行時間
Full GC的時間比Minor GC要長。所以如果執行太長時間的Full GC(超過1秒),就會發生超時錯誤
- 如果你試著減少老年代的大小來降低Full GC的執行時間,可能會引發OutOfMemoryError或者導致Full GC的頻率升高。
- 如果是通過增加老年代的大小來降低Full GC的頻率,執行時間將會增加。
影響GC的參數
JVM調優主要用到參數羅列在下面的兩張表中。主要分為內存參數和垃圾類型參數。GC優化的過程就是在調試這些參數的過程。
下表是與JVM內存相關的參數:
比較常用的參數是 -Xms
, -Xmx
和 -XX:NewRatio
下表展示的垃圾收集器類型的可選參數:
不同的垃圾回收器與老年代年輕代的關系如下:
還有一個常用的參數是-XX:+PrintGCDetails
通過 -XX:+PrintGCDetails
可以查看具體的GC日志。下面的兩張圖分別介紹Full GC與Minor GC日志里的各個字段。
監控命令
設置好上面將的參數后,可以通過監控查看我們優化的。監控可以分為命令監控和圖形化監控。關于圖形化監控可用工具比較常見的有JConsole和VisualVM,可以參考這篇文章。這里不做過多介紹。這節主要介紹個常用的監控命令,在下面的案例中也是有用到的。
jps 命令格式:jps [option] [hostid]
jps命令用于查詢正在運行的JVM進程,常用的參數為:
-q:只輸出LVMID,省略主類的名稱
-m:輸出虛擬機進程啟動時傳給主類main()函數的參數
-l:輸出主類的全類名,如果進程執行的是Jar包,輸出Jar路徑
-v:輸出虛擬機進程啟動時JVM參數
例子:
jstack 命令格式:jstack [option] vmid
用于生成當前JVM的所有線程快照,線程快照是虛擬機每一條線程正在執行的方法,目的是定位線程出現長時間停頓的原因。
-F:當正常輸出的請求不被響應時,強制輸出線程堆棧
-l:除堆棧外,顯示關于鎖的附加信息
-m:如果調用到本地方法的話,可以顯示C/C++的堆棧
例子
jmap 命令格式:jmap [option] vmid
用于顯示當前Java堆和永久代的詳細信息(如當前使用的收集器,當前的空間使用率等)
-dump:生成java堆轉儲快照
-heap:顯示java堆詳細信息(只在Linux/Solaris下有效)
-F:當虛擬機進程對-dump選項沒有響應時,可使用這個選項強制生成dump快照(只在Linux/Solaris下有效)
-histo:顯示堆中對象統計信息
例子
jstat命令格式:jstat [option vmid [interval[s|ms] [count]]]
jstat可以實時顯示本地或遠程JVM進程中類裝載、內存、垃圾收集、JIT編譯等數據
-class:監視類裝載、卸載數量、總空間及類裝載所耗費的時間
-gc:監聽Java堆狀況,包括Eden區、兩個Survivor區、老年代、永久代等的容量,以用空間、GC時間合計等信息
-gccapacity:監視內容與-gc基本相同,但輸出主要關注java堆各個區域使用到的最大和最小空間
-gcutil:監視內容與-gc基本相同,但輸出主要關注已使用空間占總空間的百分比
-gccause:與-gcutil功能一樣,但是會額外輸出導致上一次GC產生的原因
-gcnew:監視新生代GC狀況
-gcnewcapacity:監視內同與-gcnew基本相同,輸出主要關注使用到的最大和最小空間
-gcold:監視老年代GC情況
-gcoldcapacity:監視內同與-gcold基本相同,輸出主要關注使用到的最大和最小空間
-gcpermcapacity:輸出永久代使用到最大和最小空間
-compiler:輸出JIT編譯器編譯過的方法、耗時等信息
例子
命令jstat -gc 309 1000 5代表著:搜集vid為309的java進程的整體gc狀態, 每1000ms收集一次,共收集5次
案例
下面兩個案例是網友的JVM調優過程,作者過程思路清晰,步步分析到位,在這里分享給大家:
1、CMS調優
2、OOM問題調優
總結
JVM調優在實際工作中用到的比較少,但是這也是作為java程序員必須掌握的基本技能。真正熟練的使用GC調優,是建立在多次進行GC監控和調優的實戰經驗上的。
下面羅列了幾個數據作為參考,如果GC執行時間滿足下列所有條件,就沒有必要進行GC優化了:
Minor GC執行非常迅速(50ms以內)
Minor GC沒有頻繁執行(大約10s執行一次)
Full GC執行非常迅速(1s以內)
Full GC沒有頻繁執行(大約10min執行一次)
PS:如果你要應付面試上的JVM題目。這可以參考這篇文章jvm知識點總覽