What is WeakHashMap?
4. Value → Key references — memory leak! 5. Call methods regularly to trigger cleanup 6. Heap Dump — look for Entry with null referent
🟢 Junior Level
WeakHashMap is a Map where keys can be automatically removed when there are no more references to them.
Simple analogy: You put things on a shelf. If you forgot about an item and nobody needs it → the cleaner throws it away.
WeakHashMap<Object, String> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "value");
key = null; // No more references to the key!
System.gc(); // System.gc() is only a hint; in reality, removal will happen at the next GC
map.size(); // → 0 (entry removed!)
🟡 Middle Level
How it works
WeakReference — a reference that does not prevent the GC from collecting the object. If only WeakReferences point to an object, the GC will collect it.
ReferenceQueue — a queue where the GC places “dead” references. WeakHashMap periodically checks this queue.
expungeStaleEntries() — an internal method of WeakHashMap that removes entries with dead keys on every operation (get, put, size).
1. Key is wrapped in a WeakReference
2. On GC: if no strong references → key is collected
3. Entry is placed into ReferenceQueue
4. On the next call to ANY map method:
→ expungeStaleEntries() drains the queue
→ Entry is removed from the map
Pitfalls
1. String literals are never removed:
// ❌ Will never be removed!
WeakHashMap<String, String> map = new WeakHashMap<>();
map.put("literal", "value"); // Literal lives forever in the String Pool!
2. Strong reference from Value to Key:
// ❌ Memory leak!
class Value { Object keyRef; }
map.put(key, new Value(key)); // Value holds the key!
// The key will never be collected!
When to use
// ✅ Metadata for objects
WeakHashMap<Component, String> tooltips = new WeakHashMap<>();
tooltips.put(button, "Click me");
// When button is removed → tooltip will be removed automatically
// ✅ NOT for caches!
// → WeakReference is cleared on EVERY Minor GC
// → Minor GC — garbage collection in Young Generation, happens every few seconds/milliseconds when objects are actively created.
// → For caches: use Caffeine or SoftReference
// **Why NOT for caches:** WeakHashMap removes entries on EVERY Minor GC.
// If you cache the result of an expensive computation, it may disappear within milliseconds.
// Use WeakHashMap for caches only if keys are unique identity objects, not data.
// Or better — java.lang.ref.SoftReference (not collected on Minor GC).
🔴 Senior Level
ReferenceQueue mechanism
// WeakHashMap internally:
class Entry<K,V> extends WeakReference<K> {
V value;
Entry<K,V> next;
Entry(K key, V value, ReferenceQueue<K> queue) {
super(key, queue); // Queue for notifications
this.value = value;
}
}
// GC detected a weak-only key
// → Places Entry into ReferenceQueue
// → expungeStaleEntries() on the next map call
Lazy cleanup
// WeakHashMap does NOT clean itself up on its own!
// Cleanup happens when ANY method is called:
map.put(new Object(), "x");
// ... GC collected the key ...
// map still contains the "dead" entry!
map.size(); // → Only now will it be cleaned!
// → If you don't call methods for a long time → memory leak!
WeakHashMap vs alternatives
| Solution | When |
|---|---|
| WeakHashMap | Lifecycle tied to key |
| Caffeine Cache | Full-featured cache (LRU, TTL) |
| SoftReference | Cache, collected on OOM threat |
| ThreadLocal | Data tied to thread |
Difference from Map<WeakReference<K>, V>: WeakHashMap automatically removes dead entries — you don’t need to manually clean the ReferenceQueue. In Map<WeakReference<K>, V>, dead references accumulate indefinitely.
Leak diagnostics
Heap Dump: look for Entry with referent = null
→ Entry still in the table array
→ Map methods haven't been called for a while
→ "Lazy cleanup" didn't trigger
Solution: map.size() will force cleanup
Production Experience
Real scenario: Component metadata
// UI framework: metadata for components
WeakHashMap<Component, Properties> meta = new WeakHashMap<>();
// Component removed → meta cleans up automatically
// → No memory leaks!
Best Practices
- Metadata — primary use case
- NOT a cache — cleanup is too aggressive
- String literals — will never be removed
- Value → Key references — memory leak!
- Call methods regularly to trigger cleanup
- Heap Dump — look for Entry with null referent
Summary for Senior
- WeakHashMap = auto-removal by key lifecycle
- ReferenceQueue → lazy cleanup on method calls
- String literals → not removed (String Pool)
- Value → Key → strong reference = leak
- NOT a cache → use Caffeine
- Metadata → primary use case
- Heap Dump → Entry with null referent
🎯 Interview Cheat Sheet
Must know:
- WeakHashMap — keys are wrapped in WeakReference, automatically removed when no strong references exist
- ReferenceQueue — GC places “dead” references here, WeakHashMap checks the queue on any method call
- expungeStaleEntries() — lazy cleanup, called on get/put/size — if not called for a long time, memory leak occurs
- String literals are NOT removed — they live forever in the String Pool
- Strong reference from Value to Key = leak! Key will never be collected by GC
- Primary use case: metadata (tooltips, properties of UI components), NOT caches
- For caches: Caffeine (LRU, TTL) or SoftReference (not collected on Minor GC)
- Difference from Map<WeakReference
, V>: WeakHashMap automatically cleans up dead entries, no manual work needed
Frequent follow-up questions:
- Why is WeakHashMap NOT suitable for caches? — It removes entries on EVERY Minor GC. A cached result of an expensive computation may disappear within milliseconds.
- How to forcefully clean up a WeakHashMap? — Call any method: size(), get(), put(). expungeStaleEntries() will check the ReferenceQueue and remove dead entries.
- What happens if Value references Key? — A strong reference from Value prevents Key from being collected by GC — the entry will never be removed, causing a memory leak.
- Why aren’t String literals removed from WeakHashMap? — String literals live in the String Pool — they always have a strong reference from the ClassLoader.
Red flags (DO NOT say):
- ❌ “WeakHashMap is a good cache” — cleanup is too aggressive, use Caffeine instead
- ❌ “WeakHashMap cleans itself up in the background” — cleanup only happens on method calls (lazy)
- ❌ “String literals are removed from WeakHashMap” — no, they live in the String Pool forever
- ❌ “WeakReference and SoftReference are the same” — SoftReference is not collected on Minor GC, only on OOM threat
Related topics:
- [[14. What is Map and what implementations exist]]
- [[15. Difference between HashMap, LinkedHashMap, and TreeMap]]
- [[18. What is ConcurrentHashMap]]