`
yuanc00
  • 浏览: 29367 次
社区版块
存档分类
最新评论

GC问题记录 – DirectByteBuffer

    博客分类:
  • java
 
阅读更多

GC问题记录 – DirectByteBuffer


        我们的一个系统在之前的运行中发现一个问题,系统内存的占用非常高,但是通过dump JVM内存,发现java的堆内存的使用是正常的。
        经过一系列排查,发现问题主要在DirectByteBuffer的使用上面。


        1.    系统使用Netty进行服务器之间的通信,而NIO使用的DirectByteBuffer,其申请的native memory只有在old gen GC(full GC/major GC或者concurrent GC)时才可以回收。主要原理是Full GC的会对old gen做reference processing,进而可以触发Cleaner对已死的DirectByteBuffer对象做清理工作;而如果很长一段时间没做过GC或者只做了young GC,则不会在old gen触发Cleaner的工作,那么就可能让本来已经死了的、但已经晋升到old gen的DirectByteBuffer关联的native memory得不到及时释放;
        2.    为DirectByteBuffer分配空间的过程中,会通过System.gc()的显示调用强迫已经无用的DirectByteBuffer对象释放掉他们关联的native memory;但是如果系统在运行的时候,设置了JVM参数:-XX:DisableExplicitGC,那么System.gc()的显示调用将变成空调用;
        3.    此时只有自然触发old gen GC进行内存回收,或者等待native memory占用达到了设置的MaxDirectMemorySize之后,出现内存溢出;
        4.    另外,如果不使用-XX:MaxDirectMemorySize={size}进行设置,MaxDirectMemorySize其值将默认为JVM可以使用最大对内存(-Xmx)减去一个Survivor space的值。


        事实上,如果直接设置了-XX:DisableExplicitGC,并且系统运行情况良好(长时间不会出现FullGC),并且大量使用了NIO的native memory,这样将很有可能导致native memory无法及时回收,最终出现内存溢出的情况“java.lang.OutOfMemoryError: Direct buffer memory”。


        在这里,我们问题是,系统的应用内存占用量很大,而实际的堆内存占比非常小,影响到了系统的运行。
        调优方法相应的有两种:
        1.    调整-Xmx的大小;我们可以把应用的最大内存设置小一些,这样尽可能快地使native memory达到MaxDirectMemorySize的上限,进行回收。这样的话,其实应用的内存使用受到了限制,除非应用本身对于内存的使用不敏感,这样才是可行的;否则反而会浪费内存。
        2.    显式设置MaxDirectMemorySize。我们可以直接把native memory设置小一些;让native memory的回收尽可能地快。


        我们这里使用的是方案1。因为系统的特点:本身应用使用量很小,但是会通过调度运行一些任务(JOB);这些任务对内存的需求还是比较多的。所以不存在内存浪费的问题,设置-Xmx小一些,反而可以节省出来一部分的内存资源给需要调度的JOB。
        结合本次问题排查的经验,我们在排查问题的时候,需要尽可能地结合应用本身的特点,找到一些合适的解决方案。

参考资料:
http://hllvm.group.iteye.com/group/topic/28866
http://hllvm.group.iteye.com/group/topic/27945

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics