WeakMap / WeakSet: Ephemerons & Garbage Collector Reclamation
- Last updated
- Prerequisites:
- How Map and Set work
- Basics of garbage collection and object lifetimes
- weakmap
- weakset
- ephemeron
- garbage-collection
- memory
- weak-reference
Read at your depth
The practical view
WeakMap stores key → value pairs where the key is an object (or symbol) held 'weakly': the key does not keep the object alive. If the key object becomes unreachable, the entry is removed automatically, so you cannot leak memory by leaving stale metadata around. WeakSet is the same idea for a set of objects. Practical uses: caching computed results keyed by objects, storing private data per-instance (like a symbol table), and tracking 'seen' objects without preventing their collection. Because keys are weak, you cannot iterate a WeakMap or check its size — the API is deliberately limited (get, set, has, delete).
The same idea in other frameworks
React internals have used WeakMap-based caches for memoized data keyed by component/fiber objects.Angular's Ivy uses WeakMap/weak references for metadata and node registries so detached components can be reclaimed.Vue's reactivity and effect scopes use weak collections to avoid pinning component instances.Svelte 5 runtime uses WeakMaps to associate internal state with DOM nodes without leaking them.Legacy vs modern
Per-instance metadata: Map (strong) vs WeakMap (weak) for private state
A WeakMap keyed by the instance lets the instance be collected with its metadata; a Map keyed by the instance pins both forever.
const cache = new Map(); // ❌ OLD: strong key → object kept alive
cache.set(user, expensiveMeta); // user can never be GC'd while cache livesconst cache = new WeakMap(); // ✅ NEW: weak key → entry dies with the key
cache.set(user, expensiveMeta); // when `user` dies, entry is collectedInterview gotchas
Context
This tests whether you understand that the API restrictions are not arbitrary — they are a direct consequence of how ephemerons must be collected.
The mechanical answer
WeakMap keys are held weakly, so their identity can vanish at any GC cycle. If iteration or .size were available, the engine would have to keep a stable, enumerable list of live keys — which forces it to maintain strong references to them to guarantee the list remains consistent across collection. That defeats the entire purpose. The semantics require that a key's presence in the WeakMap never affect its reachability, so the only observable operations are get/set/has/delete, which do not require maintaining a stable snapshot of the key set. The engine uses an ephemeron hash table where keys are weak references and entries are swept when the key dies.
Trap
The naive answer is 'the API was just simplified for developers'. It is a fundamental GC design consequence, not a convenience choice. Another trap: assuming WeakMap values are also weak — they are not; values are strongly held, they simply die together with their key. Candidates who explain the ephemeron key/value asymmetry show real understanding.
Context
Interviewers want the marking mechanics: why weak-map handling is a separate, iterative phase of GC rather than just 'another weak reference'.
The mechanical answer
An ephemeron is a key-value pair whose value is strongly referenced but whose liveness is conditioned on the key: the value is reachable only if the key is reachable. In a tracing GC, weak-map entries cannot be marked eagerly — marking the value because the WeakMap holds it would resurrect the key (value may reference key). So the collector runs a fixpoint pass: after marking strong roots, it repeatedly checks each ephemeron; if the key is marked, it marks the value and follows its edges, repeating until no new marks occur. This guarantees a value is retained only while its key lives, even with cyclic references between keys and values.
Trap
A common trap is treating a WeakMap like 'a Map that automatically clears on some timer'. Collection is deterministic per GC mark semantics, not time-based, and it is only guaranteed to happen after the key is unreachable. Another trap: assuming WeakMap prevents ALL leaks — if the VALUE itself holds strong references to other large data, the value graph is freed only when the key dies; storing huge values per-key still costs as long as the key lives.