週期性Full GC的解決
目錄
背景
線上應用的垃圾收集出現定時Full GC的異常現象。
1) 每隔10小時觸發一次Full GC;
2) 每次Full GC持續時間約爲2~3秒;
3) 與環境無關,線上環境、測試環境都會出現此問題;
原因
1. 很多NIO框架,比如netty會有很多內存映射的代碼(memory map),而mmap的內存分配至不會在用Eden區或者old區的,是屬於堆外分配,因此,這些框架中會手動調用system.gc來回收mmap分配的空間。(system.gc觸發的是full gc,只有full gc時纔會回收mmap分配的內存)。
2. 因爲NIO框架頻繁的調用full gc 會嚴重影響性能,因此,有人加上了這個參數:-XX:+DisableExplicitGC ,用來禁止system.gc對gc的觸發。加上後system.gc()將不會觸發gc。
3. 但是,如果完全不允許手動調用gc,
* 使用了NIO或者NIO框架(Mina/Netty)
* 使用了DirectByteBuffer分配字節緩衝區
* 使用了MappedByteBuffer做內存映射
以上情況下的堆外內存又無法回收,所以,才提到了用ExplicitGCInvokesConcurrent參數來替代DisableExplicitGC。
參數說明
參數:-XX:ExplicitGCInvokesConcurrent
含義:
Enables invoking of concurrent GC by using the System.gc() request.
This option is disabled by default and can be enabled only together with the -XX:+UseConcMarkSweepGC option.
System.gc()是正常FULL GC,在STW打開此參數後,在做System.gc()時會做background模式CMS GC(-XX:+UseConcMarkSweepGC),即並行FULL GC,可提高FULL GC效率。也就是說System.gc()還是會觸發GC的,只不過不是觸發一個 完全stop-the-world的full GC,而是一次併發GC週期(注:一次併發週期其實就是在CMS下的一次gc,CMS只能用在full gc 中,所以,也是一次full gc 只不過效率比較高罷了)
默認值:
注意:該參數在允許systemGC且使用CMS GC時有效。