Diagnosing leaks in Java language code can be difficult. Usually, it requires very detailed knowledge of the application. In addition, the process is often iterative and lengthy. This section provides information about the tools you can use to diagnose memory leaks in Java language code.
Note: Besides the tools mentioned in this section, a large number of third-party memory debugger tools are available. The Eclipse Memory Analyzer Tool (MAT), YourKit (www.yourkit.com) are two examples of commercial tools with memory debugging capabilities. There are many others, and no specific product is recommended. |
The following are two utilities used to diagnose leaks in Java language code.
The NetBeans Profiler: The NetBeans Profiler can locate memory leaks very quickly. Commercial memory leak debugging tools may 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 often is sufficient to identify the root cause of the leak.
The jhat utility: The jhat
utility 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. After the dump file is created, it can be used as input to jhat
. See The jhat Utility.
The following sections describe the other ways to diagnose leaks in Java language code.
A heap dump provides detailed information about the allocation of heap memory. There are several ways to create a heap dump:
HPROF can create a heap dump if it is launched with the application. Example 3-1 shows the usage of the command.
Note: If the JVM 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 theJAVA_TOOLS_OPTIONS environment variable so that the -agentlib option is automatically added to the command line. See The JAVA_TOOL_OPTIONS Environment Variable for further information about this environment variable. |
When the application is running with HPROF, a heap dump can be created by pressing Control+\ or Control+Break (depending on the platform) in the application console. An alternative approach on Oracle Solaris and Linux operating systems is to send a QUIT signal with the kill -QUIT
pid command. When the signal is received, a heap dump is created for the process with the specified PID; in the preceding example, the file snapshot.hprof
will be created.
The heap dump file contains all the primitive data and stack traces.
A dump file can contain multiple heap dumps. If Control+\ or Control+Break is pressed a number of times then subsequent dumps are appended to the file. The jhat
utility uses the #n
syntax, to distinguish the dumps, where n
is the dump number. See HPROF.
The jmap
utility can be used to create a heap dump of a running process.
It is recommended to use the latest utility, jcmd
instead of jmap
utility for enhanced diagnostics and reduced performance overhead. See Useful Commands for jcmd Utility. The command in Example 3-2 creates a heap dump for a running process using jcmd
and results similar to the jmap
command inExample 3-3.
Regardless of how the JVM was started, the jmap
tool produces a head dump snapshot in the preceding example in a file named 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. See The jmap Utility.
Another way to create a heap dump is by using the JConsole utility. In the MBeans tab, select the HotSpotDiagnostic MBean, then the Operations display, and choose the dumpHeap operation.
If you specify the -XX:+HeapDumpOnOutOfMemoryError
command-line option while running your application, then when an OutOfMemoryError
exception is thrown, the JVM will generate a heap dump.
You can try to quickly narrow down a memory leak by examining the heap histogram. It can be obtained in several ways:
If the Java process is started with the -XX:+PrintClassHistogram
command-line option, then the Control+Break handler will produce a heap histogram.
You can use the jmap
utility to obtain a heap histogram from a running process:
It is recommended to use the latest utility, jcmd
instead of jmap
utility for enhanced diagnostics and reduced performance overhead. See Useful Commands for jcmd Utility.The command in Example 3-4 creates a heap histogram for a running process using jcmd
and results similar to the following jmap
command.
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.
You can use the jmap
utility to obtain a heap histogram from a core file as shown in Example 3-5.
For example, if you specify the -XX:+HeapDumpOnOutOfMemoryError
command-line option while running your application, then when an OutOfMemoryError
exception is thrown, the JVM will generate a heap dump. You can then execute jmap
on the core file to get a histogram, as shown in Example 3-6.
Example 3-6 shows that the OutOfMemoryError
exception was caused by the number of java.lang.String
objects (3,611,828 instances in the heap). Without further analysis it is not clear where the strings are allocated. However, the information is still useful. To continue investigation with tools such as HPROF
and jhat
to find where the strings are allocated, as well as what references are keeping them alive and preventing them from being garbage collected.
When the OutOfMemoryError exception is thrown with the "Java heap space" detail message, the cause can be excessive use of finalizers. To diagnose this, you have several options for monitoring the number of objects that are pending finalization:
The JConsole management tool 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 Oracle Solaris and Linux operating systems, the jmap
utility can be used with the -finalizerinfo
option to print information about objects awaiting finalization.
An application can report the approximate number of objects pending finalization using the getObjectPendingFinalizationCount
method of the java.lang.management.MemoryMXBean
class. Links to the API documentation and example code can be found in Custom Diagnostic Tools. The example code can easily be extended to include the reporting of the pending finalization count.