执行Java垃圾收集,但未收到GC通知

时间:2019-01-23 10:50:29

标签: java memory-management garbage-collection javabeans jmx

我遵循了来自不同来源的一些示例,并且具有以下片段:

 private void registerForMemUsageChanges() {
    List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
    for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeans) {
        listenForGarbageCollectionOn(garbageCollectorMXBean); 
    }

}

private void listenForGarbageCollectionOn(GarbageCollectorMXBean garbageCollectorMXBean) {
    NotificationEmitter notificationEmitter = (NotificationEmitter) garbageCollectorMXBean;
    GarbageListener listener = new GarbageListener();
    notificationEmitter.addNotificationListener(listener, null, null);
}

public class GarbageListener implements NotificationListener {

    @Override
    public void handleNotification(Notification notification, Object handback) {
        if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
            doSomthing();//irrelevant
        }

    }
}

我添加了一个测试,该测试可以执行以下操作(同样,根据我发现的示例),并且似乎可以正常工作:

private void triggerGc() throws InterruptedException {
    Object obj = new Object();
    WeakReference ref = new WeakReference<Object>(obj);
    obj = null;
    while(ref.get() != null) {
        System.gc();
    }
}

在调试模式下运行时,我看到侦听器已注册到ps markweep和ps scavenge。 while循环结束(我认为已执行GC),但未调用任何通知。不是GC通知或任何类型的通知。

是侦听器注册错误还是未真正执行GC的问题?在while循环之后,弱引用似乎确实为空。

我正在使用openjdk 1.8.0_144。

2 个答案:

答案 0 :(得分:0)

这是System.gc() javadoc所说的

  

调用gc方法表明Java虚拟机已消耗   努力回收未使用的对象以制造内存   它们目前可用于快速重用。控制权返回时   从方法调用来看,Java虚拟机已尽力而为   从所有丢弃的对象中回收空间。

调用垃圾收集器并不意味着将在调用时立即收集垃圾。但是通过调用gc,您只能建议JVM收集垃圾,而不能强制垃圾。

答案 1 :(得分:0)

问题实际上是: A)正如Holger在评论中提到的那样,我只是收到了影响到老一代的GC的通知,并且 B)尽管代码已经执行了,但调试器并没有在我的断点处停止,所以即使我不知道,doSomething实际上也做了一些事情。