-XX:+DisableExplicitGC弊端

总结:

如果jvm参数中设置了-XX:+DisableExplicitGC,那么代码中手动调用System.gc()就不会生效。而有些框架中因为是使用的堆外内存,必须手动调用System.gc()来释放。如果禁用掉就会导致堆外内存使用一直增长,造成内存泄露。

详解:
直接内存与System.gc()

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对象作清理工作.

CMS垃圾回收器下的推荐配置

既然不推荐使用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间隔,默认是一个小时。

System.gc常识

system.gc其实是做一次full gc
system.gc会暂停整个进程
system.gc一般情况下我们要禁掉,使用-XX:+DisableExplicitGC
system.gc在cms gc下我们通过-XX:+ExplicitGCInvokesConcurrent来做一次稍微高效点的GC(效果比Full GC要好些)
system.gc最常见的场景是RMI/NIO下的堆外内存分配等

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值