年輕代與老年代的調優(筆記整理)
幾個常見名詞
年輕代(young 區)
從年輕代空間(包括Eden和Survivor 區域)回收內存被稱為 Minor GC
空間太小可能導致對象直接進入 old區 。如果old區 滿了,會觸發full gc。但也不能過大,過大會引起回收耗時過長,導致應用阻塞。
老年代(old 區)
從老年代GC稱為Major GC
空間過小會產生old區小碎片,放不下大對象,引起頻繁full gc。如果用了緩存,old區也要適當大些,同時緩存不應無限增長。
存活區(Survivor)
Survivor的存在意義,就是減少被送到老年代的對象,進而減少Full GC的發生。
伊甸園(Eden)
整個堆內存(heap)=young+old
GC(垃圾回收機制)
堆區有兩個Survivor區,新建的對象會存活在在Eden中。Eden區如果沒有足夠的空間時會引發一次young區的GC。
在經歷一次MinorGC之后,Eden中的存活對象就會被移動到第一塊survivor space-S0,此時Eden被清空;
等Eden區再次填滿,就再觸發一次Minor GC,Eden和S0中的存活對象又會被復制送入第二塊survivor space-s1;此時S0和Eden被清空,然后下一輪S0與S1交換角色。
如果 Survivor的空間不足或經歷16次Minor GC還能在新生代中存活的對象會通過分配擔保機制被送入老年代。
老年代負責分配擔保讓Survivor無法容納的對象直接進入老年代。如果剩余空間小於轉移對象大小,將直接進行 FullGc
進入老年代的對象
- 大對象會直接進入老年代(避免頻繁復制)
- 在程序中長期持有了對象的引用(對象年齡達到指定閾值也會進入老年代)
- survivor 區太小,只能進入老年代
FullGC
執行 Minor GC(年輕代GC) 的時候,JVM 會檢查老年代中最大連續可用空間是否大於了當前新生代所有對象的總大小
如果大於,則直接執行 Minor GC(年輕代GC)(這個時候執行是沒有風險的)
如果小於,JVM 會檢查是否開啟了空間分配擔保機制,如果沒有開啟則直接改為執行Full GC
如果開啟擔保機制,則 JVM 會檢查老年代中最大連續可用空間是否大於歷次晉升到老年代中的平均大小,如果小於則執行改為執行Full GC
如果大於則會執行 Minor GC(年輕代GC),如果 Minor GC(年輕代GC) 執行失敗則會執行 Full GC
出現Full GC的時候經常伴隨至少一次的Minor GC,但不絕對。Major GC的速度一般會比Minor GC慢10倍以上
內存溢出
老年代只有在新生代對象轉入及創建大對象、大數組時才會出現空間不足的現象。當執行Full GC后空間仍然不足,則會拋出如下錯誤:
java.lang.OutOfMemoryError: Java heap space
GC頻率監控
- jstat -class 類加載統計
- jstat -compiler 編譯統計
- jstat -GC 垃圾回收統計
- jstat -gccapacity 堆內存統計
- jstat -gccnew 年輕代垃圾回收統計
- jstat -gccold 老年代垃圾回收統計
- jstat -gcnewcapacity 年輕代內存統計
- jstat -gcoldcapacity 老年代內存統計
- jstat -gcmetacapacity 元空間內存統計
- jstat -gcutil gc整體統計
- jstat -gccause gc原因
ps -eo pid,tty,user,comm,lstart,etime | grep 【pid】 查看進程運行時間
- YGCT :從應用程序啟動到采樣時年輕代中 gc 所用時間(s)
- FGC :從應用程序啟動到采樣時 old 代(fullgc)gc 次數
- FGCT :從應用程序啟動到采樣時 old 代(fullgc)gc 所用時間(s)
- GCT :從應用程序啟動到采樣時 gc 用的時間(s)
- YGC/YGCT=年輕代單次gc時間
- FGC/FGCT=fullGC單次時間
- YGC/time=年輕代gc頻率
- FGC/time=老年代gc頻率
判斷fullgc是否正常的標准:FGCT/FGC<=200ms
fullGC 頻繁出現的可能原因
- 對象引用長期未釋放
- survivor 區太小
- old 區太小
- System.gc()方法的調用
Full GC調優辦法
1:讓對象在Minor GC階段被回收、讓對象在新生代多存活一段時間及不要創建過大的對象及數組
2:年輕代小對象盡量多,大對象則盡可能直接進入老年代。年輕代由於使用標記復制算法進行回收內存,速度很快
3:Eden區如果沒有足夠的空間時會引發一次young區的GC,通過-XX:SurvivorRatio 進行調整 Eden 和 Survivor 比例大小。少量對象的存活,適合復制算法(年輕代),大量對象存活,適合標記清理或者標記壓縮(年老代)。