Memory Management and Garbage Collection
Memory Management and Garbage Collection
V8 memory allocation, Mark-and-Sweep mechanics, generational GC, and memory leak prevention.
The Hotel Room Service Cleaning Crew
JavaScript automatically manages memory by allocating space when objects are created and freeing it when they are no longer reachable. Understanding V8 garbage collection helps avoid memory leaks in large applications.
Memory Lifecycle (Allocate → Use → Release)
Allocation occurs when values are declared. Primitives and function frames live on the Stack; reference types (objects, closures, arrays) live on the unstructured Heap.
Reachability and Roots
An object is reachable if it can be accessed directly or indirectly from "Roots" (global variables, local variables in the current call stack, active closures).
Mark-and-Sweep Algorithm
The GC periodically starts at the Roots, traverses all outgoing references, and marks reachable objects. In the sweep phase, any unmarked memory is reclaimed.
V8 Generational GC (Scavenger & Major GC)
New objects are allocated in the "Nursery" (Young Generation) and cleaned up fast via Scavenge. Long-lived objects that survive two GC cycles are promoted to the "Old Generation" and collected less frequently via Mark-Sweep-Compact.
Identifying and eliminating a classic detached event listener memory leak:
// Leak Example: Lingering event listener keeping memory alive
class LeakyWidget {
constructor() {
this.heavyData = new Array(1000000).fill("payload");
this.boundHandler = this.onWindowResize.bind(this);
window.addEventListener("resize", this.boundHandler);
}
onWindowResize() {
console.log("Widget resized, data length:", this.heavyData.length);
}
// Proper Cleanup Method
destroy() {
// Crucial: remove the listener so GC can reclaim 'this' and heavyData!
window.removeEventListener("resize", this.boundHandler);
this.heavyData = null;
console.log("Widget destroyed and memory released.");
}
}
const widget = new LeakyWidget();
widget.destroy();
Widget destroyed and memory released.
Forgotten Timers and Callbacks
The Risk: `setInterval(() => { ... }, 1000)` maintains an active reference to any variables in its closure. If not cleared via `clearInterval()`, memory is never reclaimed.
The Fix: Always retain timer IDs and clear them when components unmount or operations finish.
Detached DOM Tree References
The Risk: Removing a DOM node from the document while keeping a reference to it in a JS variable prevents the entire subtree from being garbage collected.
The Fix: Nullify references to removed DOM nodes when they are removed from the view.
- ✓ Memory is automatically freed when objects become unreachable from Roots.
- ✓ Core algorithm: Mark-and-Sweep (traverse from roots, mark visited, sweep unmarked).
- ✓ V8 divides memory into Young (frequent, fast) and Old (infrequent, thorough) generations.
- ✓ Top 3 memory leaks: uncleared `setInterval`, dangling DOM event listeners, detached DOM nodes.
- ✓ Use `WeakMap` / `WeakSet` to hold object metadata without blocking garbage collection.