首页 » 漏洞 » 为什么不推荐使用-XX:+DisableExplicitGC

为什么不推荐使用-XX:+DisableExplicitGC

 
文章目录

System.gc()默认会触发一次Full Gc,如果在代码中不小心调用了System.gc()会导致JVM间歇性的暂停,但有些NIO框架

比如Netty框架经常会使用DirectByteBuffer来分配堆外内存,在分配之前会显式的调用System.gc(),如果开启了DisableExplicitGC

这个参数,会导致System.gc()调用变成一个空调用,没有任何作用,反而会导致Netty框架无法申请到足够的堆外内存,从而产生

java.lang.OutOfMemoryError: Direct buffer memory.

既然是堆外内存,为什么触发Full GC会有助于回收堆外内存呢,Full GC不是只回收JVM的堆内存吗?这就要了解下DirectByteBuffer的

回收机制了,DirectByteBuffer没有finalizer,它的native memory的清理工作是通过sun.misc.Cleaner自动完成的,而sum.misc.Cleaner

是一种基于虚引用的回收工具,从JDK源码也可以看到:

public class Cleaner extends PhantomReference<Object> 

当GC检查到Cleaner的引用变成虚引用可达时,reference-handler线程会调用Cleaner的clean方法回收内存,这个机制可以在

java.lang.ref.Reference$ReferenceHandler里看到,Reference类加载的时候会创建reference-handler线程:

public void run() {             for (;;) {                 //省略了一些                 // Fast path for cleaners                 if (r instanceof Cleaner) {                     ((Cleaner)r).clean();                     continue;                 }             } static {         ThreadGroup tg = Thread.currentThread().getThreadGroup();         for (ThreadGroup tgn = tg;              tgn != null;              tg = tgn, tgn = tg.getParent());         Thread handler = new ReferenceHandler(tg, "Reference Handler");         /* If there were a special system-only priority greater than          * MAX_PRIORITY, it would be used here          */         handler.setPriority(Thread.MAX_PRIORITY);         handler.setDaemon(true);         handler.start();     } 

JVM在做Full GC时会对引用作处理(reference processing),当GC检测到Cleaner的引用变成虚可达时,

引用Handler线程会触发Cleaner对DirectByteBuffer对象作清理工作.

ExplicitGCInvokesConcurrent

既然不推荐使用DisableExplicitGC这个参数,那有没有什么办法能尽量减少显式调用System.gc()带来的GC停顿呢,JVM提供了

ExplicitGCInvokesConcurrent和ExplicitGCInvokesConcurrentAndUnloadsClasses这两个参数来保证显式调用System.gc()

触发的是一个并发GC周期而不是Full GC,这两个参数只能配合CMS使用(-XX:+UseConcMarkSweepGC):

CMS GC周期内也会做reference-processing,因此也能够触发对DirectByteBuffer内存的回收,减少了Full GC带来的长时间

停顿.

后记

当没有开启DisableExplicitGC这个参数时,你会发现JVM每个小时会执行一次Full GC,这是因为JVM在做分布式GC,为RMI服务的,

可以通过sun.rmi.dgc.server.gcInterval这个参数来修改GC间隔,默认是一个小时,具体的参数可以参考 http://docs.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html

原文链接:为什么不推荐使用-XX:+DisableExplicitGC,转载请注明来源!

0