JavaScript's garbage collector automatically frees memory, but certain patterns prevent it from recognizing memory as collectible. This article covers how mark-and-sweep works, the four classic leak patterns, and how to debug memory issues.
Prerequisites: V8 #1 — JIT Compilation, JS Foundations #3 — Closures
1. Mark-and-Sweep — How GC Works
The garbage collector periodically finds objects that are no longer reachable from the root (global object, call stack):
Loading editor...
Generational GC: V8 splits the heap into new space (young, short-lived objects) and old space (survived multiple GC cycles). Most objects die young — the scavenger (minor GC) handles them cheaply.
2. Leak Pattern #1 — Forgotten Timers and Intervals
The most common SPA leak — intervals that keep running after a component unmounts:
Loading editor...
3. Leak Pattern #2 — Detached DOM Nodes
A JavaScript reference to a removed DOM element keeps the element in memory:
Loading editor...
4. Leak Pattern #3 — Closure Capturing Large Data
Closures capture the entire scope, not just the variables they use:
Loading editor...
5. Leak Pattern #4 — Unbounded Caches
Caches that grow without limit eventually exhaust memory:
Loading editor...
6. Detecting Leaks — The Heap Snapshot Pattern
In Chrome DevTools, the Memory panel offers heap snapshots:
Loading editor...
Key Takeaways
| Leak Pattern | Cause | Fix |
|---|---|---|
| Forgotten timers | setInterval without clearInterval | Cleanup in useEffect return / componentWillUnmount |
| Detached DOM | JS reference to removed element | Null out references when DOM elements are removed |
| Closure captures | Inner function captures entire outer scope | Extract only needed values before closing over |
| Unbounded caches | Map/Object that only ever grows | Use LRU cache with max size; TTL-based eviction |
- GC is nondeterministic — you can't force it (
window.gc()only in dev mode with--expose-gc). - Use WeakMap/WeakSet for object-associated data that shouldn't prevent GC.
- Heap snapshots are the primary debugging tool — learn to compare before/after.
Next: Engine #1 — Hoisting & TDZ Internals — what the engine actually does during parsing and execution.
