How to Find a Memory Leak in Java Production — End-to-End Investigation
Fast recall
Quick revision
Core answer
jcmd GC.class_histogram), then a heap dump at peak usage (jmap -dump or -XX:+HeapDumpOnOutOfMemoryError). Open in Eclipse MAT or VisualVM — run leak suspects and dominator tree to find objects retaining megabytes. Common culprits: static collections, ThreadLocal, unclosed listeners, ClassLoader retention.Whether you have actually debugged a production memory leak — the workflow shows real experience that surface-level GC theory cannot fake
Jumping straight to a heap dump without first confirming it's actually a leak, or restarting the JVM and 'hoping it doesn't come back' instead of finding the root cause
Mention safety considerations (heap dump pauses, container memory pressure, dump size on persistent volumes) and the discipline of post-fix verification with a second heap dump
Interview-ready guide
Interview answer
Finding a memory leak in production is a five-phase discipline: confirm, capture, analyze, fix, verify. The biggest mistake — and the one I always avoid — is bumping -Xmx and hoping the problem goes away.
Phase 1 — Confirm it's a leak:
- Use
jstat -gcor GC logs in GCEasy5000 - If post-full-GC heap baseline trends upward over hours → genuine leak
- If stable but full GC is frequent → heap is just undersized; increase
-Xmx
Phase 2 — Capture a heap dump:
- Auto on OOM with
-XX:+HeapDumpOnOutOfMemoryError(always enabled in production) - On-demand with
jcmdGC.heap_dump /path/heap.hprof - Capture two dumps several hours apart for delta analysis
- Mount a persistent volume in containers so OOM dumps survive restarts
Phase 3 — Analyze with Eclipse MAT:
- Leak Suspects report — automated; often identifies root cause in seconds
- Dominator Tree sorted by retained heap (not shallow heap)
- Path to GC Roots with weak/soft excluded — shows the reference chain holding the object alive
- Compare Snapshots between two dumps — reveals exactly what grew
Phase 4 — Fix the root cause:
- Unbounded caches → switch to Caffeine with
maximumSizeandexpireAfterWrite ThreadLocalin pooled threads → mandatoryremove()infinally- Listener registries → balanced
register/unregisterlifecycle - ClassLoader leaks in app servers → teardown hooks on undeploy
Phase 5 — Verify with another heap dump:
- Run under realistic load for hours, capture again, confirm retained heap of the suspect is now bounded
- Many fixes resolve only one of multiple leaks — verify, don't assume
In interviews, the verification step is the differentiator. Anyone can describe MAT; senior engineers always verify the fix with a second snapshot.
How to Find a Memory Leak in Java Production — End-to-End Investigation
Direct Answer
Production leak investigation: capture heap histogram (jcmd GC.class_histogram), then a heap dump at peak usage (jmap -dump or -XX:+HeapDumpOnOutOfMemoryError). Open in Eclipse MAT or VisualVM — run leak suspects and dominator tree to find objects retaining megabytes. Common culprits: static collections, ThreadLocal, unclosed listeners, ClassLoader retention.
Common Mistakes & Pitfalls
Jumping straight to a heap dump without first confirming it's actually a leak, or restarting the JVM and 'hoping it doesn't come back' instead of finding the root cause
Check your understanding
Answer these without looking back at the article.
- How would you investigate a memory leak in a Kubernetes pod where you can't easily attach a debugger?
- What's the difference between a memory leak and an undersized heap, and how do you tell them apart?
- How do you safely capture a heap dump on a production service without causing a long pause?
- Why is `ThreadLocal` a common source of memory leaks in Tomcat and Spring Boot applications?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.