HANDBOOK · JAVA HEAP DUMP ANALYSIS

Notes on Heap Dump analysis

Capture and analyze Java heap dumps with Eclipse MAT — find memory leaks, OOM root causes, and dominator retainers in production incidents.

16
Modules
6
War Stories
6
Labs
jcmd, jmap & OOM auto-dump workflows
Eclipse MAT dominator tree mastery
Kubernetes heap capture playbooks
Leak patterns: caches, ThreadLocal, sessions

When you need a snapshot of JVM state

Memory Leaks

See exactly which objects retain heap — JFR shows allocation rate, heap dumps show retainers.

OOM Incidents

Post-mortem analysis when pods OOMKill — no reproduction needed.

MAT Analysis

Dominator tree, GC roots, leak suspects, and histogram in Eclipse MAT.

17 MODULES

Guide sections

Module 1

Introduction to Heap Dumps

What hprof files are, when to use them, and how they differ from JFR.

Module 2

Why Every SRE Needs Heap Dump Skills

OOM incidents, memory leaks, and K8s OOMKilled pods require heap analysis.

Module 3

JVM Heap Memory Refresher

Young/old gen, metaspace, and what appears in hprof vs native memory.

Module 4

Capturing Heap Dumps

jcmd, jmap, OOM flags, and safe production timing.

Module 5

Heap Dump Tools Overview

Eclipse MAT, VisualVM, jhat, and when to use each.

Module 6

Eclipse MAT Fundamentals

Opening hprof, histogram, dominator tree, and leak suspects report.

Module 7

Dominator Tree & GC Roots

Understanding retention paths and why objects weren't collected.

Module 8

Memory Leak Investigation Workflow

Step-by-step SRE playbook from alert to fix.

Module 9

Analyzing OOMKilled Pods

Kubernetes OOM workflow and heap artifact recovery.

Module 10

Heap Dump vs JFR vs Native Memory

When to use each tool in the JVM observability stack.

Module 11

Kubernetes Heap Dump Capture

exec, ephemeral containers, volume mounts for hprof files.

Module 12

Spring Boot Leak Patterns

Common leaks in Spring apps: caches, sessions, actuator, class loaders.

Module 13

Database & Cache Leak Patterns

Connection wrappers, result sets, and in-memory caches.

Module 14

Production Best Practices

When to capture, security, size, and storage.

Module 15

SRE Incident War Stories

Real heap dump investigations with MAT evidence.

Module 16

Heap Dump vs Other Tools

Decision tree with JFR, jstack, strace, and NMT.

Module 17

SRE Production Playbook

End-to-end heap incident response.

Detailed Module Content

Production SRE playbooks, examples, and incident patterns

MODULE 1

Introduction to Heap Dumps

A heap dump is a snapshot of every object in the JVM heap at a point in time — classes, instances, references, and retained sizes. Saved as .hprof files.

What a Heap Dump Contains

  • All live and some unreachable objects
  • Reference graph between objects
  • Shallow and retained heap sizes
  • Thread-local and static references
Key Insight

Heap dumps answer who is holding memory — not just how fast allocations happen (that's JFR).

MODULE 2

Why Every SRE Needs Heap Dump Skills

ScenarioMetrics ShowHeap Dump Reveals
OOMKilled podMemory at limit, restartExact objects retaining 2GB
Slow memory growthHeap % climbing over daysCache class dominating dominator tree
Post-incident RCAGC logs show Full GCLeak suspect: SessionMap
SRE TIP

Enable -XX:+HeapDumpOnOutOfMemoryError on every production Java service.

MODULE 3

JVM Heap Memory Refresher

  • Young Gen: Eden + Survivor — short-lived objects
  • Old Gen: long-lived — where leaks accumulate
  • Metaspace: class metadata (separate from hprof heap in some views)
  • Native memory: not in hprof — check RSS vs heap
Shallow heap
Memory of the object itself
Retained heap
Object + exclusively retained children
MODULE 4

Capturing Heap Dumps

terminal
# Recommended (JDK 11+)
jcmd <PID> GC.heap_dump /tmp/heap.hprof

# On OOM (set at startup)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/app/heap.hprof

# Legacy
jmap -dump:live,format=b,file=heap.hprof <PID>
Production Warning

Live heap dumps trigger a stop-the-world pause. For a 8GB heap this can take 30–90 seconds. Capture during maintenance window or low traffic.

MODULE 5

Heap Dump Tools Overview

ToolBest ForProduction Use
Eclipse MATLeak analysis, dominator treeDownload hprof, analyze offline
VisualVMQuick histogramSmaller dumps, dev/staging
jhatServer-side quick viewLarge dumps on analysis server
JFRLive allocation rateComplement — not replacement
MODULE 6

Eclipse MAT Fundamentals

  1. Download Eclipse MAT (Memory Analyzer)
  2. File → Open Heap Dump (.hprof)
  3. Run Leak Suspects Report first
  4. Open Dominator Tree sorted by retained heap
  5. Use Path to GC Roots on suspicious objects
  6. Export report for postmortem
SRE TIP

Increase MAT heap: MemoryAnalyzer -vmargs -Xmx8g for large production dumps.

MODULE 7

Dominator Tree & GC Roots

The dominator tree shows objects that dominate memory — if you remove a dominator, its retained subtree becomes unreachable.

GC roots are starting points: static fields, thread stacks, JNI, class loaders. Path from root to object explains why GC kept it alive.

Immediate dominator
Parent object in retention chain
Retained set
All memory freed if object removed
MODULE 8

Memory Leak Investigation Workflow

  1. Confirm heap growth in metrics (not just RSS)
  2. Capture JFR for allocation rate (optional)
  3. Take hprof at peak or after OOM
  4. MAT Leak Suspects → Dominator Tree
  5. Identify top retainer class and reference chain
  6. Map to code: cache, ThreadLocal, static map
  7. Fix + deploy + verify heap flatlines
MODULE 9

Analyzing OOMKilled Pods

terminal
kubectl describe pod <pod> | grep -A5 OOM
kubectl logs <pod> --previous
# If heap path mounted:
kubectl cp <pod>:/var/log/app/heap.hprof ./oom.hprof

Distinguish heap OOM (Java heap space) from container memory limit (RSS includes native + metaspace + heap).

MODULE 10

Heap Dump vs JFR vs Native Memory

JFR
Live allocation rate, low overhead
Heap dump
Object graph, retainers, post-OOM
Native track
RSS > heap — NMT, pmap, container limit
MODULE 11

Kubernetes Heap Dump Capture

terminal
kubectl exec -it <pod> -- jcmd 1 GC.heap_dump /tmp/heap.hprof
kubectl cp <pod>:/tmp/heap.hprof ./heap.hprof

# Ephemeral debug container (distroless)
kubectl debug -it <pod> --image=amazoncorretto:17 --target=app --share-processes
SRE TIP

Mount emptyDir or PVC at HeapDumpPath so OOM dumps survive pod termination.

MODULE 12

Spring Boot Leak Patterns

  • @Cacheable without eviction
  • HTTP session maps in memory
  • Static singleton holding request context
  • DevTools classloader in prod (accidental)
  • Micrometer registries growing unbounded
MODULE 13

Database & Cache Leak Patterns

HikariCP proxy leak
Connection wrappers retained in static list
Query result cache
Unbounded ConcurrentHashMap of lists
MODULE 14

Production Best Practices

  • Always set HeapDumpOnOutOfMemoryError
  • Store dumps on persistent volume in K8s
  • Redact PII — heap contains live user data
  • Set retention policy — hprof files are large
  • Practice MAT workflow in staging quarterly
  • Never capture full heap on 32GB+ without approval
MODULE 15

SRE Incident War Stories

Session Cache OOM

SEV2

Impact: Checkout API down 22 min, pods OOMKilled

Symptoms: Heap 95%, Full GC every 2 min, P99 timeout

Dump evidence: MAT: SessionCache retained 4.2GB — 890k session objects, no TTL

Root cause: New feature cached full cart per session without eviction

Resolution: Added Caffeine maxSize=10k + expireAfterAccess=30m

Lesson: Leak Suspects report flagged SessionCache in 2 minutes

ThreadLocal User Context Leak

SEV2

Impact: Memory climb over 5 days, eventual OOM

Symptoms: Gradual heap growth, normal traffic

Dump evidence: Dominator: ThreadLocalMap → UserContext 2.8GB across 200 threads

Root cause: UserContext set in filter, never removed in finally block

Resolution: threadLocal.remove() in filter finally; pool threads reused

Lesson: ThreadLocal + thread pools = classic leak — always remove()

Static Map Microservice Leak

SEV3

Impact: Single service OOM every 48h

Symptoms: Predictable OOM cycle after deploy

Dump evidence: Histogram: EventDTO 12M instances in static HashMap

Root cause: Debug logging stored every event in static map 'for troubleshooting'

Resolution: Removed static map; use bounded ring buffer

Lesson: Search dominator for static fields holding collections

ClassLoader Leak on Redeploy

SEV3

Impact: Metaspace + heap growth on hot redeploys

Symptoms: Only after multiple deploys without restart

Dump evidence: GC roots: WebappClassLoader retained 1.1GB old app classes

Root cause: Thread holding reference to old classloader via shutdown hook

Resolution: Proper lifecycle on shutdown hooks; restart pod on deploy

Lesson: ClassLoader leaks show as metaspace + old gen class objects

K8s OOM Wrong Limit

SEV2

Impact: Pods killed at 512Mi limit, heap only 256MB

Symptoms: OOMKilled but small hprof — native memory issue

Dump evidence: Heap dump only 180MB; RSS was 510MB — direct buffers

Root cause: Container limit too low for heap + metaspace + Netty direct memory

Resolution: Increased limit to 1Gi, -XX:MaxDirectMemorySize=256m

Lesson: OOMKilled ≠ Java heap full — check native and direct memory

Elasticsearch Client Buffer Leak

SEV2

Impact: Ingestion service OOM during bulk indexing spike

Symptoms: byte[] dominates histogram after traffic spike

Dump evidence: Retained byte[] 3.1GB from unreleased bulk response buffers

Root cause: Exception path skipped buffer release in custom client wrapper

Resolution: try-finally on buffer release; added leak test

Lesson: byte[] top of histogram → buffer or serialization leak

MODULE 16

Heap Dump vs Other Tools

Use heap dump when you need object-level retention. Use JFR for live allocation rate. Use jstack for thread state. Use strace for OS boundary.

Leak / OOM → hprof + MATAllocation rate → JFRThreads blocked → jstackSyscall wait → strace
MODULE 17

SRE Production Playbook

Alert: heap highJFR quick checkCapture hprofMAT analysisFix retainersVerify metricsPostmortem
terminal
# Emergency checklist
jcmd <PID> VM.flags | grep HeapDump
jcmd <PID> GC.heap_dump /tmp/incident.hprof
# Open in MAT → Leak Suspects → Dominator Tree
PRACTICAL EXPERIENCE

Hands-on Labs

LAB 1

Capture live heap dump with jcmd

GC.heap_dump on a running Spring Boot service safely.

LAB 2

Analyze dominator tree in Eclipse MAT

Find top memory retainers and leak suspects.

LAB 3

Configure OOM automatic heap dump

HeapDumpOnOutOfMemoryError for post-mortem.

LAB 4

Compare two heap dumps (diff)

Baseline vs incident to find growing object types.

LAB 5

Capture heap from Kubernetes pod

kubectl exec + jcmd + kubectl cp workflow.

LAB 6

Investigate ThreadLocal leak via MAT

Find ThreadLocalMap entries retaining sessions.

TEST YOUR KNOWLEDGE

Interactive Quiz

10 questions · Instant feedback

INTERVIEW PREP

Common Interview Questions

Q1

When do you take a heap dump vs JFR?

JFR during live incident for allocation rate; heap dump when you need object retainers or post-OOM analysis.

Q2

How to capture heap dump without jmap?

jcmd <PID> GC.heap_dump /path/heap.hprof or -XX:+HeapDumpOnOutOfMemoryError.

Q3

What is dominator tree?

Tree showing which objects retain the most heap — if removed, how much memory becomes unreachable.

Q4

Common production leak patterns?

Unbounded caches, ThreadLocal, static collections, session maps, connection wrappers.

Q5

How to analyze OOMKilled pod?

Check if heap dump was written, download hprof, open in MAT, check dominator tree and leak suspects.

Q6

Heap dump too large to download?

Capture with live objects only, use MAT on server, or analyze subset with jhat remotely.

Q7

Difference shallow vs retained heap?

Shallow = object itself; retained = object + everything only reachable through it.

Q8

GC roots in MAT?

Objects reachable from JVM roots — dominator paths explain why objects weren't collected.

TROUBLESHOOTING

Investigation Flowcharts

Memory Leak

Heap growing? → JFR allocation rate → Still leaking? → Capture hprof → MAT dominator tree → Fix retainers

OOMKilled

Pod restart OOMKilled → Heap dump exists? → Open in MAT → Leak suspects → Fix + tune -Xmx

High Heap Usage

Heap > 80% → Live hprof or JFR → Old gen full? → Leak vs legit cache → Tune or fix

MAT Analysis

Open hprof → Leak Suspects report → Dominator tree → Path to GC roots → Identify fix

Production Cheat Sheet

Capture Live

jcmd <PID> GC.heap_dump /tmp/heap.hprof

OOM Auto-Dump

  • -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/heap.hprof

MAT Key Views

  • Leak Suspects
  • Dominator Tree
  • Histogram
  • Thread Overview
  • GC Roots

Common Leaks

  • Unbounded HashMap/cache
  • ThreadLocal
  • static List
  • HTTP session map
  • ClassLoader leak