1. Introduction
Memory leaks in Java applications can cause severe performance degradation, frequent OutOfMemoryError
s, and even complete system crashes. While Java has garbage collection, leaks can still occur if references to unused objects are unintentionally held.
2. What Is a Memory Leak in Java?
In Java, a memory leak occurs when an object is no longer needed but is not garbage collected because it is still referenced (directly or indirectly) from reachable code.
Example
List<String> cache = new ArrayList<>(); public void addToCache(String item) { cache.add(item); // Keeps growing indefinitely if not managed }
If cache
keeps growing, this can cause a heap memory leak.
3. Symptoms of a Memory Leak in Production
You may be facing a memory leak if you observe:
- Increasing heap usage over time (monotonic growth)
- Frequent Full GCs with little memory reclaimed
OutOfMemoryError: Java heap space
- Application becomes slow or unresponsive
- Thread dumps show GC taking too long
4. Step-by-Step: How to Debug a Memory Leak in Production JVM
Step 1: Monitor the Application
Plot heap memory over time. If it’s continuously rising and never going down even after GC, this indicates a leak.
Step 2: Enable Heap Dumps on OutOfMemoryError
In production, always configure JVM to dump heap when it crashes:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/myapp/heapdump.hprof
The heap dump will be a .hprof
file which contains the entire memory snapshot of the application at crash time.
Step 3: Analyze Heap Dump
Use a heap analysis tool to inspect the .hprof
file.
Focus on:
- Large
Map
orList
objects that grow unchecked - Custom caches without eviction
- Static fields holding large object graphs
- Listeners or observers that aren’t deregistered
- ThreadLocal leaks
- Inner classes referencing outer class unintentionally
Step 4: Take Live Heap Snapshots (Optional)
In some cases, you can connect a profiler to the live production server:
- Use JMX + VisualVM
- Or JFR (Java Flight Recorder) in Java 11+
With jcmd
you can trigger dumps live:
jcmd <pid> GC.heap_dump /path/to/heap.hprof
Make sure to avoid excessive overhead on a live system.
5. Common Causes of Memory Leaks
Source | Description |
---|---|
Static Collections | Holding references to objects forever |
Unbounded Caches | No eviction policy leads to ever-growing memory |
Listeners not removed | Event listeners (e.g., Swing, UI, observer patterns) |
ThreadLocal | Threads live long and hold large objects |
ClassLoader Leaks | Common in web applications that reload classes |
Improper use of Weak/Soft References | Not understanding their semantics |
Infinite data structures | E.g., growing HashMap , ArrayList , queues |