Overview
Garbage collection (GC) is the automatic memory management system that JavaScript engines use to reclaim memory occupied by objects that are no longer reachable. Understanding GC mechanics is essential for writing performant JavaScript applications and diagnosing memory issues.Modern JavaScript engines use sophisticated GC strategies to minimize pause times while efficiently reclaiming memory. The techniques covered here are implemented in production engines like V8, SpiderMonkey, and JavaScriptCore.
Mark-and-sweep garbage collection
Mark-and-sweep is the fundamental algorithm underlying most JavaScript garbage collectors. It operates in two distinct phases:1
Mark phase
The collector starts from root objects (global variables, stack references, active closures) and traverses the object graph, marking every reachable object.
2
Sweep phase
The collector scans through the heap, reclaiming memory from any unmarked objects. These objects are unreachable and safe to collect.
How marking works
The marking phase uses graph traversal to identify live objects:Sweep implementation
After marking completes, the sweep phase reclaims unmarked memory:Generational collection
Generational GC exploits the weak generational hypothesis: most objects die young. By dividing the heap into generations, engines can collect short-lived objects more frequently and efficiently.- Young generation
- Old generation
- Write barriers
Young generation (nursery)
New objects are allocated in the young generation, which is small and collected frequently.Characteristics:- Fast allocation (bump-pointer allocator)
- Frequent collection (minor GC)
- Low pause times (small heap region)
- High mortality rate (90%+ objects die young)
1
Scavenge
Copy live objects to a survivor space using Cheney’s algorithm
2
Promotion
Objects that survive multiple collections are promoted to old generation
3
Reclaim
Entire young generation space is reclaimed and reset
Incremental and concurrent GC
To reduce pause times, modern engines break GC work into smaller increments and perform collection concurrently with JavaScript execution.Incremental marking
Instead of marking the entire heap at once, incremental GC interleaves small marking steps with JavaScript execution.1
Start marking
Begin marking from roots in a small time slice (1-5ms)
2
Resume execution
Let JavaScript run while maintaining marking progress
3
Continue marking
Resume marking in subsequent time slices
4
Finish marking
Complete marking when the object graph is fully traversed
Incremental GC requires tri-color marking (white/gray/black) and write barriers to track objects modified during JavaScript execution between marking increments.
Concurrent marking
Concurrent GC performs marking on separate threads while JavaScript continues executing on the main thread. Benefits:- Main thread pause times reduced to microseconds
- Marking throughput increased with parallelism
- Better utilization of multi-core CPUs
- Requires thread-safe data structures
- Needs synchronization for object graph mutations
- More complex write barrier implementation
- Architecture
- Implementation
WeakMap and WeakSet implementation
Weak collections hold references that don’t prevent garbage collection, enabling memory-conscious caching and metadata storage patterns.How weak references work
Weak references are invisible to the garbage collector. An object is collectible if only weak references point to it.
WeakMap use cases
- Private data
- Caching
- Metadata
Implementation details
Ephemeron tables: WeakMap/WeakSet use ephemeron tables, where key liveness determines entry liveness.Memory profiling and leak detection
Identifying and fixing memory issues requires understanding profiling tools and common leak patterns.Using heap snapshots
1
Capture baseline
Take a heap snapshot at application start or after initialization
2
Exercise application
Perform actions that might leak memory (create/destroy components, navigate)
3
Capture comparison
Take another snapshot and compare to baseline
4
Analyze growth
Look for object types that grew unexpectedly (should have been collected)
Common memory leak patterns
- Event listeners
- Closures
- Timers
- Caches
Measuring GC impact
Target GC pause times: < 16ms for 60fps applications, < 100ms for perceived smoothness. Use incremental/concurrent GC to stay within budget.
Next steps
Event loop
Learn how JavaScript schedules asynchronous work with microtasks and macrotasks
JIT optimization
Explore how engines optimize hot code paths with just-in-time compilation