1. 程式人生 > >java nio 和 jvm 虛擬機器引數的 XX:+DisableExplicitGC 的潛規則

java nio 和 jvm 虛擬機器引數的 XX:+DisableExplicitGC 的潛規則

有段時間應用總是出現jvm所管理的記憶體沒有發生溢位的情況,而是使用的直接記憶體區域發生溢位的行為。後來經過分析情況如下:

是由於應用中使用netty,netty 使用的nio 和 jvm 中的 XX:+DisableExplicitGC配置的衝突導致的,

具體經過:nio 使用直接記憶體區域  Direct Memory記憶體回收和其他記憶體回收有點區別。Java堆內放置的是direct memory 引用,正常情況下當在young gc 的時候會把這個已死的引用回收,進而也回收了native memory 區域 , 但是有些移動到old gen區中的,在沒有發生full gc時候這個物件一直沒有被回收,然後direct memory 應該會累積。

另外當在為DirectByteBuffer分配空間過程中發現直接記憶體不足時會顯式呼叫System.gc(),以期通過full GC來強迫已經無用的DirectByteBuffer物件釋放掉它們關聯的native memory , 這個可以從java.nio的原始碼中可以分析到(DirectByteBuffer .class Bits.class):


但是導致OOM 的最終原因是jvm調優時配置了引數:

-XX:+DisableExplicitGC這個將會忽略手動呼叫GC的程式碼使得 System.gc()的呼叫就會變成一個空呼叫,完全不會觸發任何GC。

所以實際上在old gen未達到full gc的要求jvm記憶體回收正常時,而native memory (reservedMemory + size > maxMemory)已經滿了。這樣就導致了Direct Memory 的OOM

XX:+DisableExplicitGC去掉配置

另外 對於-XX:MaxDirectMemorySize引數的配置,這個引數的設定需要調整,因為這個引數的配置直接會導致full gc的頻率,影響web的整體響應情況。

當初查這個問題時一直忽略了jvm的引數被調整過的情況,導致排查過程一直反覆。所以這次也算是一次深刻的總結分享吧