Friday, September 28, 2007

Fighting the OutOfMemoryError

Searching for memory leaks in an application is always a very difficult task. I experienced memory problems in a Java web application two months ago. After running some days an OutOfMemoryException was thrown because the application went out of heap memory.

Monitoring the application with the jconsole - which is an excellent tool for this task and it is included in the Sun JDK - showed that there was an amount of heap memory that could not be garbage collected and it slightly but steady increased over time. This meant that I had to search for the references that prevent the objects from getting cleared.


The first thing I did is to create multiple histograms of the heap while working with the application, destroying the session and starting garbage collection from jconsole. I did this by using jmap which is a small tool included in Sun JDK since version 5:

jmap -histo PID > histo.txt

Of course I had to fill in the PID of the VM running my application. Comparing the generated histograms I found that the number of instances of some objects in my application got more and more. These objects should have been garbage collected because they were just entity beans that should not be referenced anymore.

To go to the next level I used new features of Sun JDK 6. The jmap version of JDK 6 has more options than the version of JDK 5 and is much faster. Creating the histogram with version 5 took 58 seconds compared to about 1 (!) second with version 6. Additionally I used the :live option of jmap 6 to get only live objects in my histogram:

jmap -histo:live PID > histo.txt

Now that I identified some suspicious objects I had to find out what references them. There is another tool that comes with Sun JDK 6 for exactly that purpose: jhat. jhat is able to analyze binary memory dump files of a Java VM. Therefor I created a dump file of my application using the following command line:

jmap -dump:live,format=b,file=heap.bin PID

This creates a binary dump file of all live objects in the VM with the given PID and writes them in the specified file. To look into the dump I run jhat like

jhat -J-mx768m heap.bin

I had to add the memory option because otherwise jhat had not enough memory to display my 50MB dump file. After the successful start of jhat I could see the following on my shell:

Reading from heap.bin...
Dump file created Thu Jun 21 11:17:40 GMT+01:00 2007
Snapshot read, resolving...
Resolving 570010 objects...
Chasing references, expect 114 dots..................................................................................................................

Eliminating duplicate references..................................................................................................................

Snapshot resolved.
Started HTTP server on port 7000
Server is ready.Pointing my browser to localhost:7000 brought up the following page:

This is a list of all the classes loaded in the VM. Now I searched for the classes I identified before in the histogram and on the details page of the class I clicked on the link named “All instances including subclasses”:

After selecting one of the instances I was able to see all other objects referencing this object instance:



The classes in the screenshots are not the classes of my project - these are just examples - but in my project I found out that the problem were references from ThreadLocals. In my web application there some persistent objects and whole transaction/sessions were bound temporary to a ThreadLocal but the references were never set to null.

In every thread of the Tomcat server (which are 25 per default) references were hold to objects that could not be garbage collected. Under load the server created even more threads which were not closed early enough to avoid the OutOfMemoryError. To fix my problem I checked my code to make sure that after each request all the ThreadLocal references were cleared - and that resolved it.

No comments: