Garbage collection
Objects created during program execution are automatically removed by a special module of Java Virtual Machine called Garbage Collector.
When an object is not referenced by any threads and when the JVM determines that this object will not be accessed, then it becomes eligible for garbage collection.
Garbage collector then removes those objects from the heap.

What is Cleaner
java.lang.Object class has a finalize method which is automatically called by the garbage collector before it attempts to remove the object from the heap.

Starting java 9, finalize method has been deprecated and a new java.lang.ref.Cleaner class is added for garbage collection management.
An object of cleaner gets notified automatically when an object becomes eligible for garbage collection or phantom reachable.
A cleaner object has a provision to take some action before the object is garbage collected, same as with finalize() method.

For this, the object that is being garbage collected needs to be registered with the cleaner object along with the action that should be taken upon garbage collection.
But first, we should understand how a cleaner object is created.
Creating Cleaner
A cleaner object can be created using its static method create as shown below.

Cleaner cleaner = Cleaner.create();

This method creates a new cleaner object and also starts a thread in the background(daemon thread) which keeps on monitoring any objects eligible for garbage collection or the objects which are phantom reachable.

Registering for cleaning actions
For registering a cleaner to perform an action before garbage collection, you need to invoke register() method of a cleaner object.

register() method accepts two arguments
1. An object which the cleaner keeps monitoring for garbage collection. When this object becomes eligible for garbage collection, the cleaner takes the specified action.

2. A java.lang.Runnable instance which represents the action to be taken.
Code snippet for the above two steps will be

cleaner.register(object, runnableInstance);

where object is the object which is being monitored for garbage collection and runnableInstance is an object implementing java.lang.Runnable.

Needless to say that the cleaning action will be performed in a new java thread.
Remember that the class implementing java.lang.Runnable should not be a java inner class(either anonymous nor non-anonymous).
This is because an inner class implicitly holds the reference to the outer object, which prevents it from being garbage collected.
Example program
Combining all the discussion, now its time to see it in real action with an example program.

import java.lang.ref.Cleaner;

public class CleanerExample {
   public static void main(String[] args) {
      // create a cleaner object
      Cleaner cleaner = Cleaner.create();
      // create an object in if-block
      if(true) {
         // object that will be garbage collected
         CleanerExample myObject = new CleanerExample();
         // register cleaner
         cleaner.register(myObject, new State());
      }
      for (int i = 1; i <= 10000; i++) {
         String[] largeObject = new String[1000];
         try {
            Thread.sleep(1);
         } catch (InterruptedException e) {
         }
      }
   }

   private static class State implements Runnable {
      public void run() {
         System.out.print("Cleaning action");
      }
   }
}

In the above example, the class State implements java.lang.Runnable and provides implementation of run method.
Note that this class is a static nested class.

Object of this class is provided as the action to be taken when the object is garbage collected. When the object is garbage collected, run method is automatically invoked.
Running this program will print Cleaning action on the console as output.

There are some important points to note about the above program

  1. The object that needs to be garbage collected is created inside an if-block that will always be executed.
    Creating an object inside a block ensures that after the block completes, there are no references to this object left which means that the object now becomes phantom reachable.
    You can also use a loop instead of an if-block.
  2. If the object is created outside the block, then it will not be eligible for garbage collection.
  3. for loop only serves the purpose of creating additional objects for memory consumption and halting program execution so that the cleaner thread sweeps out the object created inside if-block.
  4. String array created inside the loop is only for consuming the memory.
    If you comment out this line, then the object may never be garbage collected.
  5. Class implementing java.lang.Runnable should not be an inner class and the action provided to register method should not be an anonymous implementation of run().
  6. run() method should not contain any reference to the object which you want to be garbage collected.

Hope this article was useful in understanding the concept of Cleaner class introduced in java 9.
Do not forget to hit the clap below.

Leave a Reply