How to analyze Heap Dump using Eclipse Memory Analyzer (MAT)
Memory issues are among the most challenging problems Java developers face. OutOfMemoryErrors, memory leaks, and performance degradation can cripple applications in production. The key to solving these mysteries lies in understanding heap dumps and knowing how to analyze them effectively.
In this comprehensive guide, we’ll explore heap dump analysis using Eclipse Memory Analyzer Tool (MAT), one of the most powerful tools available for Java memory troubleshooting. Whether you’re debugging a legacy application or optimizing a modern microservice, this guide will equip you with the knowledge to identify and resolve memory issues.
What is a Heap Dump?
A heap dump is a snapshot of all the objects in the Java Virtual Machine (JVM) memory at a specific point in time. Think of it as taking a photograph of your application’s memory — capturing every object, their relationships, and the memory they consume.
What Information Does a Heap Dump Contain?
- All objects in memory (instances of classes)
- Primitive values and object references
- Class information and metadata
- Thread stacks and local variables
- The relationships between objects (who references whom)
What a Heap Dump Does NOT Contain
- Historical data (it’s a point-in-time snapshot)
- CPU usage information
- Code execution paths
- Garbage collection statistics
Installing Eclipse and MAT
Downloading Eclipse
Eclipse comes in various distributions. For heap dump analysis, any version works, but the Enterprise Java Edition is commonly used.
Step 1: Download Eclipse
Visit eclipse.org/downloads/packages
Choose based on your system:
- Windows x86_64: For standard Windows PCs (most common)
- Windows AArch64: For ARM-based Windows devices
- Linux x86_64: For Linux systems
- macOS x86_64: For Intel Macs
- macOS AArch64: For Apple Silicon Macs (M1/M2/M3)
Download the latest version: eclipse-jee-2024-12-R-win32-x86_64.zip
Step 2: Install Eclipse
- Extract the downloaded zip file to your preferred location (e.g.,
C:\tools\eclipse) - No installation wizard needed — Eclipse is portable
- Run
eclipse.exeto launch - Select a workspace directory when prompted
Java Requirements: Eclipse 2024–12 requires Java 17 or later. Verify your Java version:
java -versionIf you’re using older Eclipse versions (like Eclipse Kepler 4.3 from 2014), you’ll need Java 8 or Java 11. However, upgrading to the latest Eclipse is strongly recommended for better performance and features.
Installing Memory Analyzer Tool (MAT)
You have two options: standalone MAT or MAT as an Eclipse plugin.
Option 1: Standalone MAT (Recommended for Large Heap Dumps)
Standalone MAT is lighter and performs better with large heap dumps (multiple GB).
Download Standalone MAT:
- Visit eclipse.dev/mat/downloads.php
- Download “Stand-alone Memory Analyzer” for your platform
- Extract the archive
- Run
MemoryAnalyzer.exe(Windows) orMemoryAnalyzer(Linux/Mac)
Configure Memory for MAT: For large heap dumps, increase MAT’s own memory by editing MemoryAnalyzer.ini:
-vmargs
-Xmx4gThis allocates 4GB to MAT itself. As a rule of thumb, MAT needs about 1.5x the heap dump size in RAM.
Option 2: MAT as Eclipse Plugin
If you prefer working within Eclipse:
- Open Eclipse
- Go to Help → Eclipse Marketplace
- Search for “Memory Analyzer”
- Click Install on “Eclipse Memory Analyzer”
- Accept the license and restart Eclipse
Generating Heap Dumps
Before you can analyze, you need to capture a heap dump. There are several methods.
Method 1: Using jmap (JDK Tool)
The jmap command is included with the JDK:
# Find your Java process ID
jps -l# Generate heap dump
jmap -dump:live,format=b,file=heapdump.hprof <pid>Example:
jps -l
# Output: 12345 com.example.MyApplicationjmap -dump:live,format=b,file=heapdump.hprof 12345The live option triggers garbage collection before dumping, showing only live objects.
Method 2: Automatic Dump on OutOfMemoryError
Add JVM arguments to automatically generate a heap dump when an OutOfMemoryError occurs:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/logs/heapdumps/This is invaluable for production environments where you can’t manually trigger dumps.
Method 3: Using JConsole or JVisualVM
Both tools provide GUI options:
- Launch JConsole:
jconsole - Connect to your process
- Navigate to the MBeans tab
- Find
com.sun.management.HotSpotDiagnostic - Use the
dumpHeapoperation
Method 4: Programmatically
You can trigger heap dumps from within your application:
import com.sun.management.HotSpotDiagnosticMXBean;
import java.lang.management.ManagementFactory;public class HeapDumper {
public static void dumpHeap(String filePath, boolean live) {
try {
HotSpotDiagnosticMXBean mxBean = ManagementFactory
.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
mxBean.dumpHeap(filePath, live);
System.out.println("Heap dump created at: " + filePath);
} catch (Exception e) {
e.printStackTrace();
}
}
}Opening and Parsing Heap Dumps in MAT
Loading a Heap Dump
- Launch MAT (standalone or Eclipse plugin)
- File → Open Heap Dump (or drag-and-drop the .hprof file)
- MAT will parse the dump — this can take several minutes for large files
Parsing Process: MAT creates index files (.index, .threads, etc.) in the same directory as your heap dump. These speed up subsequent analyses. Don’t delete them!
Getting Started Report
After parsing, MAT displays the “Getting Started” wizard with options:
- Leak Suspects Report: Identifies potential memory leaks (best starting point)
- Component Report: Analyzes specific components
- Re-open previously run reports: Access saved analyses
For your first analysis, choose Leak Suspects Report.
Understanding the MAT Interface
Overview Tab
The Overview shows:
- Heap Size: Total memory in the dump
- Number of Classes: Unique classes loaded
- Number of Objects: Total object instances
- Number of Class Loaders: Active class loaders
Key Metrics to Understand
Shallow Heap: The memory consumed by the object itself (not including referenced objects)
Retained Heap: The total memory that would be freed if this object were garbage collected (includes all objects it keeps alive)
Retained heap is crucial for finding memory leaks because it shows the true memory impact of an object.
Core Analysis Features
1. Leak Suspects Report
MAT automatically identifies potential memory leaks using heuristics.
How to Read the Report:
- Each suspect shows a pie chart of memory distribution
- Look for suspects consuming a large percentage of heap (>10%)
- Click “Details” to see the accumulation point and shortest paths to GC roots
Example Leak Suspect:
Problem Suspect 1One instance of "com.example.CacheManager" loaded by
"sun.misc.Launcher$AppClassLoader @ 0x7f3c4d800000"
occupies 523,456,789 bytes (45.7% of total heap).The instance is referenced by:
- com.example.DataProcessor
- Thread "pool-2-thread-1"This tells you that CacheManager is holding 45.7% of your heap — a clear candidate for investigation.
2. Histogram View
The Histogram shows all classes and their instances.
Accessing: Click the “Histogram” icon in the toolbar
Key Columns:
- Class Name: Fully qualified class name
- Objects: Number of instances
- Shallow Heap: Total shallow heap for all instances
- Retained Heap: Total retained heap (if calculated)
Finding Issues:
Class Name Objects Shallow Heap Retained Heap
--------------------------------------------------------------------
byte[] 145,678 523 MB 523 MB
char[] 98,234 234 MB 234 MB
java.lang.String 87,456 2.8 MB 237 MB
com.example.Customer 45,000 1.4 MB 156 MBIf you see unexpected numbers of objects (45,000 Customer objects when you expect 100), you’ve found a leak.
Useful Histogram Techniques:
- Right-click a class → List objects → with incoming references: See what’s holding these objects
- Group by package: Right-click → Group By → Package: Identify problematic modules
- Filter by regex: Enter pattern in the filter box (e.g.,
com.example.*)
3. Dominator Tree
The Dominator Tree shows objects sorted by retained heap, revealing the biggest memory consumers.
Concept: Object A dominates object B if every path from GC roots to B must go through A.
Accessing: Click “Dominator Tree” icon or Window → Dominator Tree
Reading the Tree:
com.example.CacheManager @ 0x7a3c4d80 - 523 MB
├─ java.util.HashMap @ 0x7a3c4e00 - 520 MB
│ └─ Entry[] @ 0x7a3c5000 - 519 MB
│ ├─ Entry @ 0x7a3c5100 - 2.5 MB
│ │ └─ com.example.LargeObject - 2.5 MB
│ └─ Entry @ 0x7a3c5200 - 1.8 MBThis shows CacheManager retaining 523MB through its HashMap, which contains large objects.
4. Path to GC Roots
Understanding why an object isn’t garbage collected is crucial. The “Path to GC Roots” shows what’s keeping an object alive.
Accessing: Right-click any object → Path to GC Roots → exclude weak references
Example Path:
Thread "main" @ 0x7f3c4d900000
└─ com.example.Application @ 0x7f3c4d900100
└─ com.example.ServiceRegistry @ 0x7f3c4d900200
└─ java.util.ArrayList @ 0x7f3c4d900300
└─ com.example.Service @ 0x7f3c4d900400
└─ java.util.HashMap @ 0x7f3c4d900500
└─ YOUR LEAKED OBJECTThis path reveals that the main thread → Application → ServiceRegistry → ArrayList is preventing garbage collection.
Why Exclude Weak References? Weak, soft, and phantom references don’t prevent garbage collection, so excluding them shows the real retention paths.
5. Thread Overview
Threads can hold significant memory through their stacks and ThreadLocal variables.
Accessing: Click the “Thread Overview” icon
What to Look For:
- Threads with large retained heaps
- Many threads in WAITING or BLOCKED state
- ThreadLocal leaks (common in application servers)
ThreadLocal Leak Example:
Thread "pool-3-thread-45" - Retained Heap: 45 MB
└─ ThreadLocalMap
└─ Entry[]
└─ com.example.RequestContext - 45 MBIf you have 100 threads each holding 45MB in ThreadLocals, that’s 4.5GB of leaked memory!
6. OQL (Object Query Language)
OQL is SQL-like syntax for querying heap dumps.
Accessing: Click the “OQL” icon in toolbar
Example Queries:
Find all String objects:
SELECT * FROM java.lang.StringFind Strings containing specific text:
SELECT * FROM java.lang.String s WHERE s.value.toString() LIKE ".*password.*"Find objects with large shallow heap:
SELECT * FROM java.lang.Object WHERE @shallowHeapSize > 1000000Count instances by class:
SELECT c.name, count(*) FROM INSTANCEOF java.lang.Object o GROUP BY o.@class cFind objects created by specific class loader:
SELECT * FROM com.example.* WHERE @classLoader.@objectAddress = 0x7f3c4d800000OQL is powerful for custom queries that standard views don’t cover.
Real-World Analysis Scenarios
Scenario 1: OutOfMemoryError in Production
Symptoms: Application crashes with OutOfMemoryError after running for several hours.
Get Vinodbokare’s stories in your inbox
Join Medium for free to get updates from this writer.
Analysis Steps:
- Open the heap dump (hopefully you had
-XX:+HeapDumpOnOutOfMemoryErrorenabled) - Review Leak Suspects Report: MAT identifies that a HashMap in CacheManager is consuming 80% of heap
- Examine the HashMap:
- Open Histogram → Find HashMap
- Right-click → List objects → with outgoing references
- See 500,000 entries in the cache
- Check Path to GC Roots: The HashMap is referenced by a static field in CacheManager
- Root Cause: Cache has no eviction policy. Data keeps accumulating.
Solution: Implement LRU cache with maximum size limit or use a proper caching library like Caffeine or Guava Cache.
Scenario 2: Memory Leak with Listeners
Symptoms: Memory grows slowly over time, eventually causing OutOfMemoryError.
Analysis Steps:
- Open Histogram and look for your domain classes
- Notice 10,000 instances of
com.example.DataProcessorwhen you expect only 10 - List objects with incoming references: Each DataProcessor is referenced by an EventListener in a static EventBus
- Path to GC Roots:
EventBus (static field)
└─ CopyOnWriteArrayList (listeners)
└─ DataProcessor instances (never removed)Root Cause: Components register as event listeners but never unregister when they’re done.
Solution: Implement proper cleanup — unregister listeners when components are disposed, or use weak references for listeners.
Scenario 3: Duplicate Strings
Symptoms: Heap dump shows excessive String objects consuming memory.
Analysis Steps:
- Open Histogram → Find
java.lang.Stringandchar[] - Notice: 2 million String objects consuming 500MB
- Group by value: Right-click Strings → Group by → Value
- See many duplicate Strings with same content
- Example: “ACTIVE” appears 100,000 times
- List incoming references: These Strings come from database results or external APIs
Root Cause: Each database row creates a new String for status codes instead of reusing constants.
Solution:
// Before (creates new String each time)
customer.setStatus(resultSet.getString("status"));// After (reuses String constant)
customer.setStatus(resultSet.getString("status").intern());Or better yet, use enums:
public enum Status { ACTIVE, INACTIVE, PENDING }
customer.setStatus(Status.valueOf(resultSet.getString("status")));Scenario 4: Collection Growth
Symptoms: Application memory grows steadily, no obvious leak in custom code.
Analysis Steps:
- Dominator Tree → Expand largest objects
- Find: ArrayList with retained heap of 1.2GB
- Examine the ArrayList:
- Right-click → Java Collections → Array List Fill Ratio
- Shows: Size = 2,000,000, Capacity = 4,000,000 (50% fill ratio)
- Find what’s adding to this list:
- Path to GC Roots shows it’s in a Logger class
- Code review reveals: Logger keeps all log messages in memory for “debugging”
Root Cause: Unbounded collection that grows indefinitely.
Solution: Use a bounded queue with size limit:
// Before
private List<LogMessage> messages = new ArrayList<>();
// After
private Queue<LogMessage> messages =
new ArrayBlockingQueue<>(10000); // Max 10,000 messagesAdvanced MAT Features
Compare Heap Dumps
Comparing two heap dumps helps identify what changed over time.
Steps:
- Generate two heap dumps (e.g., before and after a suspected leak)
- Open the first dump in MAT
- File → Compare Basket or right-click → Compare To Another Heap Dump
- Select the second dump
Compare Report Shows:
- Classes with increased instance count
- Objects that appeared or disappeared
- Memory growth by class
This is invaluable for finding gradual leaks.
Batch Mode
For automation or analyzing multiple dumps, MAT supports command-line batch mode:
./MemoryAnalyzer -consolelog -application org.eclipse.mat.api.parse \
-vmargs -Xmx4g \
ParseHeapDump.sh heapdump.hprof org.eclipse.mat.api:suspectsThis generates the Leak Suspects report without opening the GUI.
Custom Queries and Extensions
MAT is extensible. You can write custom queries in Java:
@CommandName("find_large_strings")
@Category("Custom")
public class FindLargeStrings implements IQuery {
@Argument
public ISnapshot snapshot;
@Argument
public int minSize = 1000;
public IResult execute(IProgressListener listener) {
// Custom analysis logic
}
}Analyzing Collections
MAT has special support for Java collections:
- Right-click any Collection → Java Collections → Show Retained Set
- Array Fill Ratio: Shows wasted space in ArrayList, HashMap, etc.
- Collection Entries: Displays all entries in a Map or List
JVM Internals Revealed Through Heap Dumps
Heap dumps expose fascinating JVM internals. Here are insights you can gain:
String Interning
The String pool (PermGen in Java 7, Heap in Java 8+):
SELECT s, s.@retainedHeapSize FROM java.lang.String s
WHERE s.@GCRootInfo != nullThis shows interned Strings. You’ll see common strings like “” (empty string) are interned automatically.
Class Metadata
Every class in Java is an object of type java.lang.Class:
SELECT c.name, c.@retainedHeapSize FROM java.lang.Class cThis reveals which classes consume the most metadata (useful in applications with many classes).
Hidden Class Loaders
Modern frameworks create many class loaders:
Thread Overview → Examine threads → Look at their contexts
You might discover:
- Spring creates class loaders per context
- OSGi bundles have separate class loaders
- Groovy/script engines create class loaders for each script
Class loader leaks are common in application servers during hot deployment.
Finalizers
Objects with finalizers are kept in a special queue:
SELECT * FROM java.lang.ref.FinalizerIf you see thousands of objects in the Finalizer queue, it indicates:
- Finalizers aren’t running fast enough
- Objects are being created faster than finalized
- This delays garbage collection (avoid finalizers!)
Weak/Soft/Phantom References
Examine reference objects:
SELECT * FROM java.lang.ref.WeakReference
SELECT * FROM java.lang.ref.SoftReferenceThis helps understand caching strategies and potential reference leaks.
Direct Buffers
Direct ByteBuffers (off-heap memory) appear in heap dumps as small objects, but they reserve large amounts of native memory:
SELECT b, b.capacity FROM java.nio.DirectByteBuffer bThe capacity shows how much native memory each buffer reserves. If you have many DirectByteBuffers, you might hit native memory limits even though heap usage looks fine.
Best Practices and Tips
Taking Heap Dumps
- Use
-XX:+HeapDumpOnOutOfMemoryErrorin production - Take multiple dumps to identify trends
- Document the state when capturing (e.g., “after 4 hours of load test”)
- Include GC logs alongside heap dumps for complete picture
Analyzing Heap Dumps
- Start with Leak Suspects: Let MAT’s heuristics guide you
- Focus on retained heap: It shows true memory impact
- Follow the references: Use “Path to GC Roots” to understand retention
- Compare business logic vs framework: Don’t optimize framework internals
- Reproduce with smaller dataset: Makes analysis faster
Performance Considerations
- MAT needs memory: Give it 1.5x the heap dump size
- Use standalone MAT for large dumps (>2GB)
- Keep index files: They speed up reopening dumps
- Filter early: Use regex in histogram to focus on relevant classes
- Dispose results: Close unused query results to free MAT memory
Common Pitfalls
- Confusing shallow and retained heap: Focus on retained for leak analysis
- Ignoring GC roots: An object might look leaked but is actually reachable
- Over-analyzing framework classes: Look at your application classes first
- Taking dumps during GC: Wait for GC to complete for accurate results
- Not excluding weak references: Include them and you’ll see false retention paths
Integrating Heap Dump Analysis into Your Workflow
Development Phase
- Use profilers (YourKit, JProfiler) for real-time analysis
- Take heap dumps before/after tests to verify cleanup
- Review heap dumps in code reviews for memory-intensive features
Testing Phase
- Include heap dump collection in load tests
- Set up automated heap dump capture on memory thresholds
- Compare heap dumps at different load levels
Production
- Enable
-XX:+HeapDumpOnOutOfMemoryError - Monitor heap usage trends with APM tools
- Have a runbook for analyzing production heap dumps
- Consider scheduled heap dumps during maintenance windows
Tools Complementing MAT
While MAT is excellent for heap dump analysis, consider these complementary tools:
JProfiler: Real-time profiling with heap dump analysis
YourKit: Commercial profiler with excellent UI and heap analysis
VisualVM: Free tool bundled with JDK, lighter than MAT but less powerful
JFR (Java Flight Recorder): Records JVM events over time (complements heap dumps)
Eclipse Memory Analyzer Charts: Visualizations for heap dump trends
jhat: JDK heap analysis tool (deprecated, use MAT instead)
Conclusion
Heap dump analysis is an essential skill for Java developers. Eclipse MAT provides powerful capabilities to uncover memory leaks, optimize memory usage, and understand JVM behavior.
The key to mastery is practice. Start with simple scenarios, understand the core concepts (shallow vs retained heap, GC roots, dominators), and gradually tackle more complex analyses.
Remember:
- Memory leaks often hide in unexpected places (listeners, caches, ThreadLocals)
- Retained heap tells the true story of memory consumption
- Path to GC Roots explains why objects aren’t collected
- Compare heap dumps to identify trends
- Combine heap dumps with GC logs and profiling for complete diagnosis
With the knowledge from this guide, you’re equipped to tackle even the toughest memory issues. Download MAT, capture a heap dump from your application, and start exploring. You’ll be amazed at what you discover about your application’s memory behavior!
Additional Resources
- Eclipse MAT Documentation: eclipse.dev/mat
- Java Memory Management Whitepaper: Oracle’s official guide
- “Java Performance” by Scott Oaks: Comprehensive book on Java optimization
- “Optimizing Java” by Benjamin J. Evans: Modern Java performance guide
- MAT GitHub: github.com/eclipse-mat/mat
Happy analyzing!







