JavaScript Memory Management and Garbage Collection
JavaScript automatically manages memory — allocating it when variables and objects are created and freeing it when they are no longer needed. Understanding this process helps write more efficient applications and avoid memory leaks that can slow down or crash a browser.
How Memory Works in JavaScript
Memory usage in JavaScript follows three stages:
- Allocation — Memory is assigned when a variable, object, or function is created
- Use — The memory is read from and written to during execution
- Release — Memory is freed when the value is no longer reachable
let name = "Rohan"; // Memory allocated for string
let scores = [90, 85, 78]; // Memory allocated for array
let user = { id: 1 }; // Memory allocated for object
// When these variables go out of scope or are set to null,
// memory becomes eligible for garbage collectionThe Stack and the Heap
| Memory Area | What It Stores | Management |
|---|---|---|
| Stack | Primitive values (numbers, strings, booleans, null, undefined, symbols) | Automatically managed — fast allocation and release |
| Heap | Objects, arrays, functions | Managed by Garbage Collector |
let a = 10; // Stored in stack
let b = "Hello"; // Stored in stack
let obj = { x: 1 }; // Object stored in heap; reference stored in stackWhat is Garbage Collection?
Garbage Collection (GC) is the automatic process of finding and freeing memory that is no longer reachable — memory that no part of the program can access anymore.
JavaScript's main garbage collection algorithm is called Mark and Sweep.
Mark and Sweep Algorithm
- The GC starts from "roots" — global variables, the call stack, and other always-accessible references
- It marks everything reachable from roots
- Everything not marked (unreachable) is swept (deleted) and memory is freed
Reachability — The Core Concept
An object is kept in memory if it is reachable — if there is any path to it from a root. If an object becomes unreachable, it will be collected.
let user = { name: "Priti" }; // Object is reachable via "user"
user = null; // Reference removed — object is now unreachable
// Object { name: "Priti" } is eligible for garbage collectionObject Still Reachable via Another Reference
let a = { name: "Kiran" };
let b = a; // Two references to the same object
a = null; // One reference removed
// Object is still reachable via b — NOT collected
b = null; // Last reference removed — NOW it will be collectedCircular References
Modern garbage collectors handle circular references. Two objects referencing each other are still collected if neither is reachable from the roots.
function createCycle() {
let objA = {};
let objB = {};
objA.ref = objB; // A references B
objB.ref = objA; // B references A (circular!)
}
createCycle();
// After function returns, both objA and objB are unreachable from the global root
// Modern GC handles this — both will be collectedCommon Causes of Memory Leaks
A memory leak occurs when memory that should have been released continues to be held. This causes the application to consume more and more memory over time.
1. Global Variables
// Bad — accidentally creating global variable (no let/const/var)
function setup() {
leakedVar = "This is global!"; // No keyword — attached to window!
}
// Fix: always use let, const, or var
function setup() {
let safeVar = "Properly scoped.";
}2. Forgotten Timers
// Bad — interval keeps running even if the page moves on
let data = { bigArray: new Array(10000).fill("item") };
let interval = setInterval(() => {
console.log(data.bigArray.length);
}, 1000);
// If interval is never cleared, data is kept in memory forever
// Fix: always clear intervals when done
clearInterval(interval);
data = null;3. Detached DOM Elements
// Bad — element removed from DOM but still referenced in JavaScript
let detachedNode;
function createAndDetach() {
let el = document.createElement("div");
document.body.appendChild(el);
detachedNode = el; // Saved reference
document.body.removeChild(el); // Removed from DOM
}
// el is removed from the page but detachedNode still holds a reference
// → Memory leak!
// Fix: clear the reference when done
detachedNode = null;4. Closures Holding References
function outer() {
let largeData = new Array(100000).fill("data");
return function inner() {
// Even if inner() doesn't use largeData,
// some older engines may keep it in memory anyway
console.log("inner called");
};
}
let fn = outer();
// fn (inner) keeps the outer scope alive
// Fix: set fn = null when no longer needed
fn = null;5. Event Listeners Not Removed
// Bad — listener added every time function runs, never removed
function addHandler() {
document.getElementById("btn").addEventListener("click", function() {
console.log("Clicked");
});
}
// Calling addHandler() 10 times = 10 duplicate listeners
// Fix: use named function and removeEventListener when done
function handleClick() {
console.log("Clicked");
}
document.getElementById("btn").addEventListener("click", handleClick);
// When no longer needed:
document.getElementById("btn").removeEventListener("click", handleClick);Memory-Efficient Practices
- Use
constand block scope (let) to limit variable lifetime - Clear intervals and timeouts when they are no longer needed
- Set DOM references to
nullwhen elements are removed - Remove event listeners when components are destroyed
- Prefer
WeakMapandWeakSetfor object-keyed data — they do not prevent GC - Avoid creating large arrays or strings in loops unnecessarily
WeakRef — Weak Reference to an Object
A WeakRef holds a weak reference to an object — the GC can still collect the object even while the WeakRef exists.
let user = { name: "Neel" };
let weakRef = new WeakRef(user);
console.log(weakRef.deref()?.name); // "Neel" — object still alive
user = null;
// At some later point, the GC may collect the object
// weakRef.deref() may return undefined after thatChecking Memory Usage
In Chrome DevTools, the Memory tab provides heap snapshots, allocation timelines, and memory profiling to identify leaks.
- Press F12 → Memory tab → Take Heap Snapshot
- Look for objects with unexpected retention (high retained size)
- Use "Record allocation timeline" for long-running operations
Key Points to Remember
- JavaScript automatically allocates and frees memory through garbage collection
- The Mark and Sweep algorithm removes objects that are no longer reachable from the global root
- Primitive values live on the stack; objects live on the heap
- Memory leaks occur when references to unused objects are unintentionally kept alive
- Common leak causes: global variables, forgotten timers, detached DOM nodes, undone event listeners
- Use
WeakMapandWeakSetfor object associations that should not prevent garbage collection - Use browser DevTools Memory tab to profile and find memory leaks in real applications
