Tuesday, September 16, 2014

Analyzing Memory leaks: Finalize

A Constructor is used whenever we want to create a Object. A finalizer is just an Opposite of the Constructor. A constructor method performs initialization for an object; a finalizer method performs finalization for the object. Where do we use this finalizer? As we know Garbage Collector take care of cleaning the memory used by Objects but Objects can hold many types of resources like Sockets, Open File handlers etc. The garbage collector cannot free these resources for you, so you need to help the GC by writing a finalizer method for objects that needs to perform such tasks as closing files, terminating network connections, deleting temporary files.

We know that Object Class is the super class of all Classes. If we check the java.lang.Object we can see a method called “finalize”. The implementation of this method is empty but when over ridden by the sub-class it gives you a lot of power. Here is the sample Class by which we will see the danger in not using the finalize method correctly. Here is a Sample code which will create the finalize objects.

public class finalizer {
    @Override
    protected void finalize() throws Throwable {
    while (true) {
           Thread.yield();
      }
  }

public static void main(String str[]) {
  while (true) {
        for (int i = 0; i < 100000; i++) {
            finalizer force = new finalizer();
        }
   }
 }
}

When we run the code, we can see large number of Finalizer objects is being created in the undermined loop. After running for some time we will face 2 cases.
1. The JVM crashes generating use a Java heap dump
2. The JVM throws a
    Out of Memory: GC OverHead limit exceeded.

In both the cases , the JVM crashes. So what exactly happens when a finalize method is used. JVM creates a Watcher called for each and every one of the Finalizable instances. This is called Finalizer. So Whenever a Object with the finalizer method is created, a corresponding java.lang.ref.Finalizer object is created. Now since these objects are being references by the finalizer objects, these may take fill up the space in Eden causing these objects to move from Eden to Old Space.

How does the GC works with these Objects?
Now since Old space is filling up, a GC runs and only after this the GC the JVM determines that these objects are being referenced only by finalizer objects and nothing more. These objects are then marked for GC and ready for cleaning. So the GC add all Finalizer objects to a special queue at java.lang.ref.Finalizer.ReferenceQueue.

Only when all this process is completed, the application threads start to work.

How does these finalize objects are cleaned?
Once the objects are set for cleaning, a JVM thread is created called “finalizer”. If we check the thread dump for the process we can see a thread called

"Finalizer" daemon prio=10 tid=0x0962d000 nid=0x4836 runnable [0xafaa8000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.Thread.yield(Native Method)
        at finalizer.finalize(finalizer.java:5)
        at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
        at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:83)
        at java.lang.ref.Finalizer.access$100(Finalizer.java:14)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:160)

These is only one responsibility for this thread. This continuously checks the java.lang.ref.Finalizer.ReferenceQueue Queue for new objects. So when ever a new objects enters the Queue, the finalizer thread run the finalize method for that object and removes the finalizer reference for that object. So in the next GC cycle we will have this object and finalizer object both cleaned up.

Most cases the finalizer thread is fast enough to clean the finalizer Queue by running the finalize method but in our case, the finalizer is not fast enough to clean the objects that we create.  One of the reasons is that the finalizer thread is low priority thread causing to take less CPU time.

Hence the JVM crashes with Out of Memory exceptions or by generating a Heap dump.

So It is always important to write a Finalize() method to do a clean up but it is also important not to use high number of finalize objects . One way is to deal with these is to increase the priority of the "Finalizer" daemon thread - there is no API for this, so you have to run through all the threads to find it by name, then increase it's priority.

We can take control over the finalization by removing the finalize() method and using our own explicit queue using your own Reference objects in a very similar way that the Finalizer class processes the objects and their finalize() methods

How does we find how many Finalizer objects exist?
We can use the jmap command as

tmp $ jmap -finalizerinfo 18360
Attaching to process ID 18360, please wait...
Number of objects pending for finalization: 4150245
…..

How much memory does the finalizer objects take?
We can use the jmap command here too like
tmp $ jmap -histo:live 14773

 num     #instances         #bytes  class name
----------------------------------------------
   1:      24855236      795367552  java.lang.ref.Finalizer
   2:      24855230      198841840  finalizer


An article can be found on how to find the finalizer leaks using Eclipse memory analyzer here.

No comments :

Post a Comment