Close

Java Garbage Collection - Using Java 9 Cleaner to receive notification when target object is due for garbage collection

[Updated: Apr 27, 2018, Created: Apr 26, 2018]

Java 9 new class java.lang.ref.Cleaner can be used to get notification when the object has become phantom reachable (finalized and due for removal from memory).

Cleaner class uses PhantomReference and ReferenceQueue (last tutorial) to notify registered Runnable when the reachability changes.

Example

public class MyObject {
  private String id;

  public MyObject(String id) {
      this.id = id;
  }
}

Using Cleaner

The instance of Cleaner can be created by the following factory method:

static Cleaner create()

To register an cleaning 'action' for the object, we need to use following method:

Cleaner.Cleanable register(Object obj, Runnable action)

The returned object Cleanable can be used to invoke the cleaning runnable action forcefully even before object is due for garbage collection; we need to use Cleanable#clean() for that.

Let's see a very simple example:

public class CleanerExample {
    public static void main(String[] args) {
        Cleaner cleaner = Cleaner.create();
        for (int i = 0; i < 10; i++) {
            String id = Integer.toString(i);
            MyObject myObject = new MyObject(id);
            cleaner.register(myObject, new CleanerRunnable(id));
        }

        //myObjects are not reachable anymore
        //do some other memory intensive work
        for (int i = 1; i <= 10000; i++) {
            int[] a = new int[10000];
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
            }
        }
    }

    private static class CleanerRunnable implements Runnable {
        private String id;

        public CleanerRunnable(String id) {
            this.id = id;
        }

        @Override
        public void run() {
            System.out.printf("MyObject with id %s, is gc'ed%n", id);

        }
    }
}
MyObject with id 7, is gc'ed
MyObject with id 6, is gc'ed
MyObject with id 4, is gc'ed
MyObject with id 5, is gc'ed
MyObject with id 9, is gc'ed
MyObject with id 8, is gc'ed
MyObject with id 2, is gc'ed
MyObject with id 3, is gc'ed
MyObject with id 0, is gc'ed
MyObject with id 1, is gc'ed

We ran above code with JVM option -Xmx3m -Xms3m.

Note that the cleaning Runnable should not contain the the target object's instance because that will prevent it from becoming phantom reachable. Also we should not use the cleaning Runnable as inner or anonymous classes of the target Object because they implicitly contain a reference to the outer instance. (more info here).

From API docs:

The cleaning action is invoked only after the associated object becomes phantom reachable, so it is important that the object implementing the cleaning action does not hold references to the object.
The cleaning action could be a lambda but all too easily will capture the object reference, by referring to fields of the object being cleaned, preventing the object from becoming phantom reachable.

Example Project

Dependencies and Technologies Used:

  • JDK 9
  • Maven 3.3.9

Cleaner Example Select All Download
  • java-gc-cleaner-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • CleanerExample.java

    See Also