JavaScript automatically reclaims memory for objects that are no longer reachable, using algorithms like mark-and-sweep and generational collection — understanding roughly how this works demystifies both memory leaks and certain performance characteristics.
1Garbage Collection | JavaScript Tutorial - In-Depth Guide Part 1
JavaScript engines use 'mark-and-sweep' garbage collection: periodically, the engine marks every object reachable from a set of 'roots' (global variables, currently executing function scopes), then sweeps away (frees) everything left unmarked.
// Roots: global variables, the call stack's active variables
// Mark: trace every object reachable from roots
// Sweep: free everything that wasn't markedMark-and-Sweep
2Garbage Collection | JavaScript Tutorial - In-Depth Guide Part 2
Reachability, not reference count, determines whether an object survives — even a group of objects referencing only EACH OTHER (a cycle) gets collected if nothing from a root can reach any of them.
function makeCycle() {
const a = {};
const b = {};
a.other = b;
b.other = a; // circular reference to each other
} // once makeCycle() returns, neither a nor b is reachable from any root — both get collectedCycles Are Handled Correctly
3Garbage Collection | JavaScript Tutorial - In-Depth Guide Part 3
Modern engines use 'generational' collection: most objects die young, so a fast, frequent 'minor GC' scans only recently-created objects (the young generation), while a slower, less frequent 'major GC' scans everything.
// Young generation: short-lived objects, scanned frequently (fast, cheap)
// Old generation: long-lived objects that survived several minor GCs, scanned less oftenGenerational Collection
4Garbage Collection | JavaScript Tutorial - In-Depth Guide Part 4
You cannot force garbage collection from standard JavaScript code — there's no reliable, standard API to trigger it on demand, by design.
// No standard way to do this:
// forceGarbageCollection(); // does not exist in standard JSYou Can't Force It
5Garbage Collection | JavaScript Tutorial - In-Depth Guide Part 5
Setting a variable to 'null' doesn't itself free memory — it simply removes one reference, which only matters if it was the LAST reference keeping that object reachable.
let data = { big: new Array(1000000) };
const alsoReferences = data;
data = null; // doesn't free the array — alsoReferences still points to it!Setting to null Is Not Magic
6Step-by-Step Breakdown
JavaScript engines use 'mark-and-sweep' garbage collection: periodically, the engine marks every object reachable from a set of 'roots' (global variables, currently executing function scopes), then sweeps away (frees) everything left unmarked.
Reachability, not reference count, determines whether an object survives — even a group of objects referencing only EACH OTHER (a cycle) gets collected if nothing from a root can reach any of them.
Checkpoint: Does mark-and-sweep garbage collection correctly free two objects that only reference each other (a cycle), if nothing else references either of them?
- →Yes, since neither is reachable from any root
- →No, circular references always leak in JavaScript
Modern engines use 'generational' collection: most objects die young, so a fast, frequent 'minor GC' scans only recently-created objects (the young generation), while a slower, less frequent 'major GC' scans everything.
You cannot force garbage collection from standard JavaScript code — there's no reliable, standard API to trigger it on demand, by design.
Setting a variable to 'null' doesn't itself free memory — it simply removes one reference, which only matters if it was the LAST reference keeping that object reachable.
Checkpoint: If two variables both reference the same object and you set one of them to null, is the object immediately freed?
- →Yes, setting any reference to null frees the object
- →No, not while the other variable still references it
Next, we'll explore 'The Module Pattern'.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Efficient Garbage Collection Contributes to a Consistently Responsive Assistive Technology Experience
While developers don't directly control garbage collection timing, avoiding unnecessary object churn (allocating and discarding large temporary structures in hot paths) reduces GC pressure, helping keep the main thread responsive for keyboard navigation and other accessibility-critical interactions.
SEO Implications
- 1
No Direct SEO Effect
Garbage collection is an engine-internal mechanism; SEO relevance is limited to the indirect performance benefits of writing memory-efficient code that avoids GC-related jank.
Best Practices
Reason About Memory in Terms of Reachability, Not Reference Counting or Manual Deallocation
JavaScript's garbage collector is entirely reachability-based; understanding this correctly predicts why circular references don't leak, and why nulling one of several references doesn't necessarily free anything.
Don't Try to 'Help' the Garbage Collector with Manual Tricks Unless You've Confirmed an Actual Leak
Scattering `obj = null` everywhere defensively adds noise without benefit in most cases; focus effort on the small set of well-known leak patterns (listeners, timers, unbounded caches) instead.
Frequent Bugs
Believing that setting a variable to null always immediately frees the memory it pointed to, when other references to the same object may still exist elsewhere.
Understand that memory is freed only once an object becomes completely unreachable from every root — nulling one reference only matters if it was the last one.
Worrying that circular references (two objects referencing each other) will cause a permanent memory leak in JavaScript, based on experience with older reference-counting garbage collectors in other contexts.
Modern JavaScript engines use mark-and-sweep collection, which correctly identifies and frees unreachable cycles — circular references are not inherently a leak source in JavaScript, unlike in some reference-counting systems.
Real-World Examples
Explaining Why a Callback Doesn't Leak Despite Referencing Its Enclosing Scope
A developer was concerned that a closure capturing a large object would leak memory forever, and needed to understand when it would actually become eligible for collection.
function createHandler(largeData) {
return function handler() {
console.log(largeData.length);
};
}
let fn = createHandler(hugeArray);
// fn (and the closure over hugeArray) is collectible once fn itself becomes unreachable
fn = null; // now, if this was the last reference to that handler and its closure, it's collectible