1. 程式人生 > 實用技巧 >效能測試-GC問題整理

效能測試-GC問題整理

年輕代與老年代的調優(筆記整理)

幾個常見名詞

年輕代(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 比例大小。少量物件的存活,適合複製演算法(年輕代),大量物件存活,適合標記清理或者標記壓縮(年老代)。