• No results found

Diagnosing Leaks in Java Language Code

Diagnosing leaks in Java language code can be a difficult task. In most cases it requires very detailed knowledge of the application. In addition the process is often iterative and lengthy.

This section provides the following subsections:

“3.3.1 NetBeans Profiler” on page 77

“3.3.2 Using the jhat Utility” on page 77

“3.3.3 Creating a Heap Dump” on page 77

“3.3.4 Obtaining a Heap Histogram on a Running Process” on page 79

“3.3.5 Obtaining a Heap Histogram at OutOfMemoryError” on page 79

“3.3.6 Monitoring the Number of Objects Pending Finalization” on page 80

“3.3.7 Third Party Memory Debuggers” on page 80

3.3.1 NetBeans Profiler

The NetBeans Profiler (previously known as JFluid) is an excellent profiler, which can locate memory leaks very quickly. Most commercial memory leak debugging tools can often take a long time to locate a leak in a large application. The NetBeans Profiler, however, uses the pattern of memory allocations and reclamations that such objects typically demonstrate. This process includes also the lack of memory reclamations. The profiler can check where these objects were allocated, which in many cases is sufficient to identify the root cause of the leak.

More details can be found athttp://profiler.netbeans.org.

3.3.2 Using the jhat Utility

The jhat utility (see“2.5 jhat Utility” on page 39) is useful when debugging unintentional object retention (or memory leaks). It provides a way to browse an object dump, view all reachable objects in the heap, and understand which references are keeping an object alive.

To use jhat you must obtain one or more heap dumps of the running application, and the dumps must be in binary format. Once the dump file is created, it can be used as input to jhat, as described in“2.5 jhat Utility” on page 39.

3.3.3 Creating a Heap Dump

A heap dump provides detailed information on the allocation of heap memory. The following sections describe several ways to produce a heap dump:

“3.3.3.1 HPROF Profiler” on page 78

“3.3.3.2 jmap Utility” on page 78

“3.3.3.3 JConsole Utility” on page 78

“3.3.3.4 -XX:+HeapDumpOnOutOfMemoryError Command-line Option” on page 78

3.3.3.1 HPROF Profiler

The HPROF profiler agent can create a heap dump while the application is executing. The following is an example of the command line:

$ java -agentlib:hprof=file=snapshot.hprof,format=b application

If the VM is embedded or is not started using a command line launcher that allows additional options to be provided, then it might be possible to use the JAVA_TOOLS_OPTIONS environment variable so that the -agentlib option is automatically added to the command line. See“A.2 JAVA_TOOL_OPTIONSEnvironment Variable” on page 123for further information on this environment variable.

Once the application is running with HPROF, a heap dump is created by pressing Ctrl-\ or Ctrl-Break (depending on the platform) on the application console. An alternative approach on Solaris OS and Linux is to send a QUIT signal with the kill -QUIT pid command. When the signal is received, a heap dump is created; in the above example the file snapshot.hprof is created.

The heap dump file contains all the primitive data and stack traces.

A dump file can contain multiple heap dumps. If Ctrl-\ or Ctrl-Break is pressed a number of times then the subsequent dumps are appended to the file. The jhat utility uses the #n syntax to distinguish the dumps, where n is the dump number.

3.3.3.2 jmap Utility

A heap dump can also be obtained using the jmap utility (see“2.7 jmap Utility” on page 46). The following is an example of the command line:

$ jmap -dump:format=b,file=snapshot.jmap process-pid

Regardless of how the Java VM was started, the jmap tool will produce a head dump snapshot, in the above example in a file called snapshot.jmap. The jmap output files should contain all the primitive data, but will not include any stack traces showing where the objects have been created.

3.3.3.3 JConsole Utility

Another way to obtain a heap dump is with the JConsole utility. In the MBeans tab, select the HotSpotDiagnosticMBean, then the Operations display, and choose the dumpHeap operation.

3.3.3.4 -XX:+HeapDumpOnOutOfMemoryError Command-line Option

If you specify the -XX:+HeapDumpOnOutOfMemoryError command-line option, and if an OutOfMemoryErroris thrown, the VM generates a heap dump.

3.3 Diagnosing Leaks in Java Language Code

3.3.4 Obtaining a Heap Histogram on a Running Process

You can try to quickly narrow down a memory leak by examining a heap histogram. This information can be obtained in several ways:

A heap histogram can be obtained from a running process using the command jmap -histo pid. The output shows the total size and instance count for each class type in the heap. If a sequence of histograms is obtained (for example, every 2 minutes), then you might be able to observe a trend that can lead to further analysis.

On Solaris OS and Linux, the jmap utility can also provide a histogram from a core file.

If the Java process is started with the -XX:+PrintClassHistogram command-line option, then the Ctrl-Break handler will produce a heap histogram.

3.3.5 Obtaining a Heap Histogram at OutOfMemoryError

If you specify the -XX:+HeapDumpOnOutOfMemoryError command-line option, and if an OutOfMemoryErroris thrown, the VM generates a heap dump. You can then use the jmap utility to obtain a histogram from the heap dump.

If a core file is produced when the OutOfMemoryError is thrown, you can execute jmap on the core file to get a histogram, as in the following example.

$ jmap -histo \

/java/re/javase/6/latest/binaries/solaris-sparc/bin/java core.27421

Attaching to core core.27421 from executable

/java/re/javase/6/latest/binaries/solaris-sparc/bin/java, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 1.6.0-beta-b63

Iterating over heap. This may take a while...

Heap traversal took 8.902 seconds.

Object Histogram:

Size Count Class description

---86683872 3611828 java.lang.String

20979136 204 java.lang.Object[]

403728 4225 * ConstMethodKlass 306608 4225 * MethodKlass 220032 6094 * SymbolKlass 152960 294 * ConstantPoolKlass 108512 277 * ConstantPoolCacheKlass 104928 294 * InstanceKlassKlass

68024 362 byte[]

65600 559 char[]

31592 359 java.lang.Class 27176 462 java.lang.Object[]

25384 423 short[]

17192 307 int[]

:

The example shows that the OutOfMemoryError is caused by the number of java.lang.String objects (3611828 instances in the heap). Without further analysis it is not clear where the strings are allocated. However, the information is still useful and the investigation can continue with tools such as HPROF or jhat to find out where the strings are allocated, as well as what references are keeping them alive and preventing them from being garbage collected.

3.3.6 Monitoring the Number of Objects Pending Finalization

As noted in“3.1.1 Detail Message: Java heap space” on page 74, excessive use of finalizers can be the cause of OutOfMemoryError. You have several options for monitoring the number of objects that are pending finalization.

The JConsole management tool (see“2.3 JConsole Utility” on page 32) can be used to monitor the number of objects that are pending finalization. This tool reports the pending finalization count in the memory statistics on the “Summary” tab pane. The count is approximate but it can be used to characterize an application and understand if it relies a lot on finalization.

On Solaris OS and Linux, the jmap -finalizerinfo option prints information on objects awaiting finalization.

An application can report the approximate number of objects pending finalization using the getObjectPendingFinalizationCountmethod in the

java.lang.management.MemoryMXBeanclass. Links to the API documentation and example code can be found in“2.17 Developing Diagnostic Tools” on page 70. The example code can easily be extended to include the reporting of the pending finalization count.

3.3.7 Third Party Memory Debuggers

In addition to the tools mentioned in the previous chapters, there are a large number of third-party memory debuggers available. JProbe from Quest Software, and OptimizeIt from Borland are two examples of commercial tools with memory debugging capability. There are many others and no specific product is recommended.

3.3 Diagnosing Leaks in Java Language Code