What is WeakHashMap?
WeakHashMap stores keys as weak references (WeakReference): 4. "Dead" entries are removed from the table
🟢 Junior Level
WeakHashMap is a special Map that automatically removes entries when there are no more references to the key.
Simple analogy: Imagine you tie notes to balloons. When the balloon flies away (the key is garbage collected), the note disappears too.
Example:
WeakHashMap<Object, String> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "Some data");
System.out.println(map.size()); // 1
key = null; // No more references to the key
System.gc(); // only a recommendation — GC may not run
System.out.println(map.size()); // 0 (if GC ran) or 1 (if not)
When to use: For caching metadata tied to objects you don’t control.
🟡 Middle Level
How It Works
WeakHashMap stores keys as weak references (WeakReference):
- GC detects that only a weak reference remains for the key
- Puts the reference in a
ReferenceQueue - On the next WeakHashMap operation,
expungeStaleEntries()is called - “Dead” entries are removed from the table
When WeakHashMap Will NOT Remove Entries
The key will be collected by GC only when there are no strong references to it. If someone OUTSIDE the WeakHashMap holds a strong reference to the key — entries will never be removed:
Object key = new Object();
strongRef = key; // someone else holds a reference
map.put(key, "value");
key = null;
System.gc();
// Key NOT removed — strongRef still exists!
map.size(); // 1
Real memory leak: when you forgot to remove the strong reference to the key, and WeakHashMap is “waiting” for GC.
Use Cases
- Metadata caching — attaching data to objects from foreign code
- Lapsed Listener — storing listeners without preventing GC
- Thread-local data — ThreadLocal alternative
What WeakHashMap Does NOT Do
| Feature | WeakHashMap | Real Cache (Caffeine) |
|---|---|---|
| Auto-cleanup by GC | Yes | No |
| LRU/LFU eviction | No | Yes |
| TTL (lifetime) | No | Yes |
| Cache size | Unlimited | Limited |
| Thread safety | No | Yes |
Common Mistakes
- Using string literals as keys — they’re in the String Pool, never removed
- Expecting instant cleanup — cleanup is lazy, only on access
- Forgotten strong reference — someone outside the Map holds a reference to the key, GC won’t remove it
🔴 Senior Level
Internal Implementation
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
int hash;
Entry<K,V> next;
Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K,V> next) {
super(key, queue); // Key — WeakReference with queue
this.value = value;
this.hash = hash;
this.next = next;
}
}
ReferenceQueue Mechanism
// On every operation:
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null;) {
synchronized (queue) {
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);
// Remove Entry from the chain
}
}
}
Cleanup is lazy — only on get, put, size, containsKey, etc.
Reachability and GC
Java determines object reachability:
- Strong reachability: regular references → not removed
- Soft reachability: via SoftReference → removed on low memory
- Weak reachability: via WeakReference → removed on next GC
- Phantom reachability: via PhantomReference → for post-mortem cleanup
WeakHashMap uses Weak → object is removed on the next GC, even if there’s plenty of memory.
Edge Cases
- Integer Cache (-128 to 127): Integer keys from the cache are never removed
- String Pool: String literals — strong references from the JVM
- Thread safety: WeakHashMap is not thread-safe — external synchronization is needed
When NOT to Use
- Production caching: Use Caffeine/Guava Cache with LRU + TTL
- High-throughput: WeakHashMap is slower than HashMap due to ReferenceQueue polling
- Concurrent access: Need
Collections.synchronizedMap(new WeakHashMap<>())
Production Monitoring
For analyzing WeakHashMap:
- Monitor
size()— sharp decrease = GC activity - Heap dump shows ReferenceQueue with pending entries
- JFR: GC events correlate with WeakHashMap cleanup
🎯 Interview Cheat Sheet
Must know:
- WeakHashMap automatically removes entries when there are no strong references to the key
- Keys stored as WeakReference + ReferenceQueue; cleanup is lazy (on get/put/size)
- GC removes the key only when there are no strong references OUTSIDE the WeakHashMap
- Strong reference to key = entries NOT removed (real memory leak)
- Do NOT use string literals as keys — they’re in String Pool, never removed
- Not for production caching — use Caffeine/Guava Cache with LRU + TTL
Common follow-up questions:
- Why doesn’t System.gc() guarantee removal? — it’s only a recommendation, JVM may ignore it
- When won’t WeakHashMap remove entries? — someone outside the Map holds a strong reference to the key
- Is WeakHashMap thread-safe? — no, needs Collections.synchronizedMap()
- How does WeakReference differ from SoftReference? — Weak is removed on any GC, Soft — only on low memory
Red flags (DO NOT say):
- “WeakHashMap = a full-featured cache” — no, no TTL, LRU, or size limit
- “GC runs immediately after key = null” — no, System.gc() is only a recommendation
- “The value is also a weak reference” — no, only the key; value = strong reference
Related topics:
- [[12. Can You Use a Mutable Object as a Key in HashMap]]
- [[28. How to Choose the Initial Capacity for HashMap]]
- [[23. What is ConcurrentHashMap and How Does It Differ from HashMap]]