Wednesday, February 25, 2009

Diagnosing Memory Leaks Using Heap Dumps, jmap, and jhat

JConsole is a great tool for detecting memory leaks. Once you have detected a memory leak, however, you need to look further to identify what classes and objects are being leaked, and jConsole is of limited use here. Profiling tools can be a good help here, but tend to be complicated to set up and use. We look at a few profiling tools in this chapter. If you need a quick diagnosis, one alternative is to use some of the tools bundled with the JDK 6 such as jmap and jhat. In this section, we will go through how to use these tools to hunt down memory leaks by analyzing the JVM heap with these tools.

If you just want to take a quick glance at the heap of a running application, you can use the jmap command-line tool to find the PID of the Java application you are interested in (see Section 18.2), and run the jmap command with the -histo option, as follows:

$ jmap -histo 1060
num #instances #bytes class name
--------------------------------------
1: 97929 4769472 [Ljava.lang.Object;
2: 40390 4685944 <constMethodKlass>
3: 116050 4642000 com.equinox.jpt.modelplanes.core.domain.ModelPlane
4: 40390 3232240 <methodKlass>
5: 164315 2629040 java.lang.Long
6: 4862 2597352 [B
7: 44929 2516024 org.hibernate.engine.EntityEntry
8: 53272 2369464 <symbolKlass>
9: 4217 2182784 [I
10: 89833 2155992 java.util.HashMap$Entry
...


This will list the number of instances and total size occupied by objects of each class, sorted by size. This can sometimes give you some good leads. For example, if you see any of your own classes in the top 10, it's probably a bad sign and should be investigated further.

Using jmap alone can be a good first approach, but it has its limits. A more sophisticated approach is to use jhat. The jhat command-line tool, new to Java 6, is a powerful way of investigating the JVM heap. The first thing you need is a heap dump to analyze. One way is to use the jmap command-line tool, which can obtain the heap dump of a running Java application. Find the PID of the Java application you are interested in (see Section 18.2), and run the jmap command with the -dump option, as follows:



$ jmap -dump:file=dump.bin 1060
Dumping heap to /home/john/dump.bin ...
Heap dump file created

This will generate a binary dump of the JVM heap in a file called dump.bin.

Another option if you suspect memory leaks on a production is to start your application with the -XX:+HeapDumpOnOutOfMemoryError command-line option. This won't prevent any memory leaks, but it will cause the VM to generate a heap dump, enabling you to analyze the heap afterward, using jhat or some other tool.



Now we need to be able to inspect the contents of the heap dump. This is where jhat comes into action. It analyzes a binary heap dump, and starts up a web server on a local port where you can interactively explore and query the Heap Dump. You run it as follows (the -J-Xmx384m allows a maximum heap space of 384 MB; this option is not mandatory, but jhat is fairly demanding in resources, so you should give it a fair bit of memory to work with):



$ jhat -J-Xmx384m dump.bin
Reading from dump.bin...
Dump file created Tue Dec 26 13:20:27 NZDT 2006
Snapshot read, resolving...
Resolving 949898 objects...
Chasing references, expect 189 dots.............................................
................................................................................
................................................................
Eliminating duplicate references................................................
................................................................................
.............................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.



You can now connect to this site with your favorite browser. The jhat web site won't win any prizes for its elegant design or usability, but it can provide some useful information. The first place to look is the heap histogram, which provides a list of the objects in the Heap (see Figure 18-9). This is similar to the jmap histogram, but with the additional possibility to sort by size, class, or object count, and to display the class details. In Figure 18-9, it is fairly easy to see that there may be an issue with the ModelPlane. (This is of course a simple example where a memory leak was inserted on purpose; memory leaks involving Strings or other commonly used classes are usually much harder to isolate.)





Figure 18-9. The jhat class histogram



image



If you click on one of the classes in this page, you will go to the class details page, which displays general information about the class (superclasses, subclasses, members, and so forth), as well as a list of classes that refer to this class. This page also lets you build root reference chains, which are arguably the most useful feature of jhat. You will find these under "Reference Chains from Rootset," in a section inconspicuously entitled "Other Queries" at the bottom of the screen. A reference chain lists the references to this object, going back up to the root thread (see Figure 18-10). The heap histogram can indicate which objects have been leaked. Using these chains, you can get a fairly good idea of where these leaked objects are being held.





Figure 18-10. A root reference query



image

No comments:

Post a Comment