Sitemap
Vinodbokare

Vinodbokare

Passionate about clean architecture, open source, and learning something new every day. https://www.linkedin.com/in/vinod-bokare-01209370/

How to analyze Heap Dump using Eclipse Memory Analyzer (MAT)

12 min readDec 15, 2025

--

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.

Press enter or click to view image in full size
mat tool heap analysis

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

  1. Extract the downloaded zip file to your preferred location (e.g., C:\tools\eclipse)
  2. No installation wizard needed — Eclipse is portable
  3. Run eclipse.exe to launch
  4. Select a workspace directory when prompted

Java Requirements: Eclipse 2024–12 requires Java 17 or later. Verify your Java version:

java -version

If 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:

  1. Visit eclipse.dev/mat/downloads.php
  2. Download “Stand-alone Memory Analyzer” for your platform
  3. Extract the archive
  4. Run MemoryAnalyzer.exe (Windows) or MemoryAnalyzer (Linux/Mac)

Configure Memory for MAT: For large heap dumps, increase MAT’s own memory by editing MemoryAnalyzer.ini:

-vmargs
-Xmx4g

This 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:

  1. Open Eclipse
  2. Go to Help → Eclipse Marketplace
  3. Search for “Memory Analyzer”
  4. Click Install on “Eclipse Memory Analyzer”
  5. 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.MyApplication
jmap -dump:live,format=b,file=heapdump.hprof 12345

The 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 dumpHeap operation

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

  1. Launch MAT (standalone or Eclipse plugin)
  2. File → Open Heap Dump (or drag-and-drop the .hprof file)
  3. 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 1
One 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 MB

If 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 MB

This 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 OBJECT

This 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 MB

If 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.String

Find 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 > 1000000

Count instances by class:

SELECT c.name, count(*) FROM INSTANCEOF java.lang.Object o GROUP BY o.@class c

Find objects created by specific class loader:

SELECT * FROM com.example.* WHERE @classLoader.@objectAddress = 0x7f3c4d800000

OQL 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:

  1. Open the heap dump (hopefully you had -XX:+HeapDumpOnOutOfMemoryError enabled)
  2. Review Leak Suspects Report: MAT identifies that a HashMap in CacheManager is consuming 80% of heap
  3. Examine the HashMap:
  • Open Histogram → Find HashMap
  • Right-click → List objects → with outgoing references
  • See 500,000 entries in the cache
  1. Check Path to GC Roots: The HashMap is referenced by a static field in CacheManager
  2. 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:

  1. Open Histogram and look for your domain classes
  2. Notice 10,000 instances of com.example.DataProcessor when you expect only 10
  3. List objects with incoming references: Each DataProcessor is referenced by an EventListener in a static EventBus
  4. 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:

  1. Open Histogram → Find java.lang.String and char[]
  2. Notice: 2 million String objects consuming 500MB
  3. Group by value: Right-click Strings → Group by → Value
  • See many duplicate Strings with same content
  • Example: “ACTIVE” appears 100,000 times
  1. 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:

  1. Dominator Tree → Expand largest objects
  2. Find: ArrayList with retained heap of 1.2GB
  3. Examine the ArrayList:
  • Right-click → Java Collections → Array List Fill Ratio
  • Shows: Size = 2,000,000, Capacity = 4,000,000 (50% fill ratio)
  1. 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 messages

Advanced MAT Features

Compare Heap Dumps

Comparing two heap dumps helps identify what changed over time.

Steps:

  1. Generate two heap dumps (e.g., before and after a suspected leak)
  2. Open the first dump in MAT
  3. File → Compare Basket or right-click → Compare To Another Heap Dump
  4. 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:suspects

This 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 != null

This 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 c

This 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.Finalizer

If 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.SoftReference

This 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 b

The 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

  1. Use -XX:+HeapDumpOnOutOfMemoryError in production
  2. Take multiple dumps to identify trends
  3. Document the state when capturing (e.g., “after 4 hours of load test”)
  4. Include GC logs alongside heap dumps for complete picture

Analyzing Heap Dumps

  1. Start with Leak Suspects: Let MAT’s heuristics guide you
  2. Focus on retained heap: It shows true memory impact
  3. Follow the references: Use “Path to GC Roots” to understand retention
  4. Compare business logic vs framework: Don’t optimize framework internals
  5. Reproduce with smaller dataset: Makes analysis faster

Performance Considerations

  1. MAT needs memory: Give it 1.5x the heap dump size
  2. Use standalone MAT for large dumps (>2GB)
  3. Keep index files: They speed up reopening dumps
  4. Filter early: Use regex in histogram to focus on relevant classes
  5. Dispose results: Close unused query results to free MAT memory

Common Pitfalls

  1. Confusing shallow and retained heap: Focus on retained for leak analysis
  2. Ignoring GC roots: An object might look leaked but is actually reachable
  3. Over-analyzing framework classes: Look at your application classes first
  4. Taking dumps during GC: Wait for GC to complete for accurate results
  5. 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!

--

--

Written by Vinodbokare

Passionate about clean architecture, open source, and learning something new every day. https://www.linkedin.com/in/vinod-bokare-01209370/