'Java garbage collection is performed, but GC notification is not received

I have followed a few examples from various sources, and have the following snippet:

 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
        }

    }
}

I have added a test that does the following (again, based on examples I found) and it seems to work:

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

While running in debug mode I see that the listener is registered to ps marksweep and ps scavenge. The while loop finished (which I take as a sign that GC was performed) but no notification is called. Not a GC notification or of any type.

Is the problem that the listener is registered wrong or was GC not really performed? it seems that the weak ref is indeed empty after the while loop.

I am using openjdk 1.8.0_144.



Solution 1:[1]

The problem actually was:

  1. As Holger mentioned in a comment, I was only getting notification for GC that affected the old generation, and
  2. Debugger did not stop at my breakpoint, though the code was executed, so even though I couldn't tell, doSomething actually did something.

Solution 2:[2]

This is what System.gc() javadoc says

Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

Calling garbage collector does not means that garbage will collected immediately on call. But by calling gc you can only suggest JVM to collect garbage but cannot force it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Gray
Solution 2 Tarun