How can a memory leak happen in Java even with garbage collection?
A leak happens when objects are no longer needed but are still reachable, so GC cannot free them. Common causes are growing static collections, unremoved listeners, unclosed resources and keys in a map that are never removed.
Explain it simply
The garbage collector throws away only what nobody can reach. If you keep an old bus ticket in your wallet "just in case", it stays forever. A leak is a program that keeps holding references it will never use again.
Example
import java.util.*;
class SessionCache {
private static final Map<String, byte[]> CACHE = new HashMap<>(); // lives as long as the JVM
static void onLogin(String userId) {
CACHE.put(userId, new byte[1_000_000]); // added for every user...
}
// ...but nothing ever calls CACHE.remove(userId), so memory only grows
}What to say in the interview
"In Java a leak means unintended reachability. Typical sources are static collections or caches with no eviction, listeners and callbacks that are registered but never removed, ThreadLocal values in pooled threads, and objects whose mutated keys can no longer be found in a map. Fixes are bounded caches with an eviction policy, WeakHashMap or soft references for caches, try-with-resources for connections, and removing listeners. I find them with a heap dump in a tool such as Eclipse MAT, looking for what dominates retained memory."
Common mistakes
- Thinking that garbage collection makes leaks impossible.
- Using an unbounded HashMap as a cache.