Analyze Offline Java Heap Dumps
Java Heap Dumps are snapshots of the memory of a Java process at a particular moment in time. They contain information about the Java objects and classes in the heap, including references, sizes, and memory usage. Analyzing heap dumps is crucial when diagnosing memory leaks, performance bottlenecks, or unexpected behavior in Java applications. Let us delve into understanding how to analyze offline heap dumps effectively to diagnose memory issues and optimize application performance.
1. What is Heap Dump?
A heap dump is a snapshot of the memory of a Java application at a specific point in time, capturing details about all the objects, classes, and references present in the Java heap. It provides valuable information for diagnosing memory-related issues such as memory leaks and performance problems by allowing developers to analyze how memory is allocated and identify which objects are consuming the most space.
1.1 Capture Heap Dump
A heap dump can be generated in various ways:
- Using JVM Options: Add
-XX:+HeapDumpOnOutOfMemoryErrorto your Java command line. This will generate a heap dump when an OutOfMemoryError occurs. - Using jcmd or jmap: The
jcmdorjmaptools can request a running JVM to dump its heap.
Example command to capture heap dump with jmap:
jmap -dump:live,format=b,file=heapdump.hprof <pid>
Replace <pid> with the actual process ID of your Java application.
1.2 Analyzing the Heap Dump with VisualVM
VisualVM is a free visual tool for monitoring, troubleshooting, and profiling Java applications. It supports heap dump analysis with an intuitive GUI.
- Open VisualVM and load the heap dump file by choosing File > Load.
- Once loaded, you can explore object instances, memory usage by classes, and analyze memory leaks using the Heap Dump tab.
- VisualVM provides powerful filters, reference chains, and dominator tree views to understand which objects consume the most memory.
1.3 Analyzing the Heap Dump with Eclipse Memory Analyzer Tool (MAT)
Eclipse MAT is a powerful Java heap analyzer designed to handle large heap dumps. It helps identify memory leaks and reduce memory consumption.
- Open MAT and import the heap dump file.
- Run the Leak Suspects Report to get an automatic analysis of suspicious memory retention.
- Explore histograms, dominator trees, and object queries to dive deep into memory usage.
- MAT supports OQL (Object Query Language) for advanced searches inside the heap dump.
1.4 Common Causes of Memory Leaks in Java
Understanding common causes of memory leaks helps focus your heap dump analysis. Some typical causes include:
- Static Collections: Static fields holding references to objects, preventing their garbage collection.
- Listener or Callback Registrations: Objects registered as listeners that are never deregistered.
- Caches Without Eviction: Unbounded caches that keep growing over time.
- Unclosed Resources: Streams, connections, or threads that remain open and retain memory.
- ThreadLocal Variables: Improper use of ThreadLocal variables causing objects to stay alive beyond their expected lifecycle.
1.5 Best Practices for Heap Dump Analysis
To ensure effective heap dump analysis and avoid pitfalls, follow these best practices:
- Analyze on a Machine with Sufficient Memory: Heap dumps can be large; use a machine with enough RAM to handle analysis tools smoothly.
- Use Filters: Narrow down the analysis by filtering on suspicious classes or packages to avoid information overload.
- Compare Multiple Heap Dumps: Analyze heap dumps taken at different times to identify growth patterns or object retention trends.
- Generate Heap Dumps in Controlled Environments: When possible, avoid capturing heap dumps on live production systems during peak load to prevent performance impact.
- Leverage Automated Reports: Use built-in reports like Eclipse MAT’s Leak Suspects report to get initial guidance.
- Document Findings: Keep detailed notes of findings during analysis to aid troubleshooting and knowledge sharing.
2. Generating and Triggering a Heap Dump
The following Java program creates objects continuously to simulate memory usage, triggering an OutOfMemoryError to generate a heap dump (if -XX:+HeapDumpOnOutOfMemoryError is enabled).
// HeapDumpExample.java
import java.util.ArrayList;
import java.util.List;
public class HeapDumpExample {
static class LargeObject {
private byte[] data = new byte[1024 * 1024]; // 1 MB per object
}
public static void main(String[] args) {
List<LargeObject> list = new ArrayList<>();
int counter = 0;
try {
while (true) {
list.add(new LargeObject());
counter++;
if (counter % 10 == 0) {
System.out.println("Created " + counter + " LargeObjects");
}
// Slight delay to observe output clearly
Thread.sleep(100);
}
} catch (OutOfMemoryError e) {
System.err.println(
"OutOfMemoryError caught after creating " + counter + " objects");
// JVM will generate heap dump if enabled
} catch (InterruptedException e) {
System.err.println("Interrupted: " + e.getMessage());
}
}
}
2.1 Code Explanation
This program continuously creates instances of LargeObject, each allocating roughly 1MB of memory. The objects are stored in a list to prevent garbage collection. Eventually, the heap fills up, causing an OutOfMemoryError to be thrown. If the JVM is started with the -XX:+HeapDumpOnOutOfMemoryError option, it will create a heap dump file at the point of failure.
2.2 Code Run and Output
Run the program with:
java -XX:+HeapDumpOnOutOfMemoryError -Xmx100m HeapDumpExample
This limits the heap to 100MB and enables heap dump generation on memory exhaustion.
Created 10 LargeObjects Created 20 LargeObjects Created 30 LargeObjects ... Created 90 LargeObjects OutOfMemoryError caught after creating 96 objects Heap dump file written to java_pid1234.hprof
You can now use any of the tools mentioned above to analyze the heap dump.
Sign up

