If you read part 1 of this blog, you’ll know that the leaky code is part of an application1 that records stock/share orders in a dummy database using the Producer Consumer pattern. The sample code has been written to contain a very obvious flaw, namely that the OrderRecord can’t keep up with the OrderFeed. This means that the Order queue gets bigger and bigger until finally, the application runs out of heap space and falls over. The thing is, looking at my simple code, the problem should be obvious, but what if you've never seen the code before and it's huge, complex industrial strength code, plus there's no simple monitoring thread to keep an eye on the queue size or other internals? What do you do then?
Their are three steps required to find the problem with a leaky application:
- Take a dump of the leaky server's heap.
- Use the heap dump to generate a report.
- Analyse the report.
There are several tools you can use to create a heap dump file. These include:
- jconsole
- jvisualvm
- eclipse Memory Analyser Tool (MAT)
Taking a heap dump with jconsole
Connect jconsole connected to your application. Click on the MBeans tab and open the com.sun.management package. Then, click on HotSpotDiagnostic. Open Operations and select dumpHeap. You will now see the dumpHeap operation, which takes two parameters p0 and p1. Type a filename for the heap dump into the p0 edit box and press the dumpHeap button.
Taking a heap dump with jvisualvm
When connected to the sample code, right click on your application in the left hand 'application' pane and select 'Heap Dump'.
Note that if you have a remote connection to your leaky server, then jvisualvm will store the dump file in the remote machine's /tmp directory (assuming it’s a Unix box). You will have to FTP this file across to your machine for further analysis.
Taking a heap dump with MAT
Whilst jconsole and jvisualvm are part of the JDK, MAT, or memory analyser tool, is an eclipse based tool that you can download from eclipse org
The current version of MAT requires the 1.6 jdk installed on your PC. If you're using Java 1.7, don't worry, it'll install 1.6 for you and it won't mess up the rest of your machine and the default 1.7 version.
When using MAT, it's a matter of clicking on 'Aquire Heap Dump' and following the instructions.
Remote Connections
The thing to note here is that if you're trying to figure out why a production server is falling over, then you'll probably have to connect remotely using JMX and for that you'll need the following command line options, which I’ve repeated from my previous blog:
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
When to Take a Heap Dump
This takes a bit of thought and a bit of luck. If you acquire your heap dump too early then you can’t see the problems because they’re masked by legitimate, non-leaking class instances; however, don’t wait too long because taking a heap dump requires memory and therefore the act of taking a heap dump may cause your app to crash.
The best idea is to attach jconsole to you app and monitor its heap until it looks like it’s on the verge of collapse. This is easy to spot as the three heap section indicators are all green:
Analysing the Heap Dump
This is where MAT comes in to it's own as it was designed to analyse heap dumps. To open and analyse a heap dump, select File | Open Heap Dump. After choosing your heap dump file, you will now be given three choices as shown below:
Choose: Leak Suspect Report. MAT will now churn away for a few seconds before producing a page that looks something like this:
The pie chart demonstrates that in this case there is one main leak suspect. You may be thinking that this is a bit of a fix, after all this is sample code, what do you expect? Well, yes, in this case it’s very clear cut; suspect ‘a’ takes up 98.7MB whilst the rest of the objects in memory use the other 1.5MB. The fact this that you do get leak suspect pie charts in real-life situations that look like this.
The next thing to do is to dig a little deeper…
The next part of the report, shown above, tells us that there’s a LinkedBlockingQueue that’s using 98.46% of the memory. To investigate this further, click on Details>>.
This reveals that the problem is indeed our orderQueue, which is accessed by the three objects from my previous blog: OrderFeed, OrderRecord and OrderMonitor and, as we know from the code, contains a whole bunch of Order objects.
So, that’s it; MAT has told us that the sample code has a LinkedBlockingQueue that using up all the sample application’s heap space causing huge problems. It hasn’t told us why this is happening and you can’t really expect it to. That’s a matter of, as Agatha Christie’s Hercule Poirot would say, using “ze little grey cells”...
1The source code can be found in my Producer Consumer project on GitHub.
Thanks to Annika Kapur for sending me the link to this useful blog on memory leaks: Hunting Memory Leaks in Java by JOSE FERREIRA DE SOUZA FILHO.
2 comments:
You have another option to take heap dump. You can run JVM with "heap dump on OOM" parameter.
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath
Even more, when your JVM already crashed by OOM. At this moment you can take heap dump to. By jhat tool.
Post a comment