Memory Management in JavaScript
How Memory Works
JavaScript automatically allocates memory when values are created and frees it when they are no longer used. This process is called Garbage Collection.
Memory Lifecycle
- Allocate — Memory is allocated when you declare variables, objects, or functions.
- Use — Read/write operations on the allocated memory.
- Release — Memory is freed when it's no longer needed.
Stack vs Heap
| Feature | Stack | Heap |
|---|---|---|
| Stores | Primitives & references | Objects & functions |
| Size | Fixed, small | Dynamic, large |
| Access | Fast (LIFO) | Slower (random access) |
| Management | Automatic (scope-based) | Garbage collected |
// Stack: primitive value stored directly
let name = "Ajay"; // stored on stack
// Heap: object stored on heap, reference on stack
let user = { name: "Ajay" }; // reference on stack → object on heap
Garbage Collection
JavaScript uses automatic garbage collection. The main algorithm is Mark-and-Sweep:
- The GC starts from root objects (global object, local variables in current scope).
- It marks all objects reachable from roots.
- It sweeps (frees) all unmarked (unreachable) objects.
Reference Counting (older approach)
Counts how many references point to an object. When count reaches 0, object is freed. Problem: fails with circular references.
// Circular reference — wouldn't be freed by reference counting
function createCycle() {
let a = {};
let b = {};
a.ref = b;
b.ref = a;
// After function returns, mark-and-sweep CAN collect these
// Reference counting would NOT collect them
}
Common Memory Leaks
1. Accidental Globals
function leak() {
name = "oops"; // no let/const/var — creates global variable
}
2. Forgotten Timers
const timer = setInterval(() => {
// holds reference to outer scope
console.log("running...");
}, 1000);
// Fix: clearInterval(timer) when done
3. Detached DOM References
let button = document.getElementById("btn");
document.body.removeChild(button);
// 'button' variable still holds a reference — memory not freed
button = null; // Fix: remove the reference
4. Closures Holding Large Data
function outer() {
let bigData = new Array(1000000).fill("x");
return function inner() {
// inner() keeps bigData alive even if it doesn't use it
console.log("hello");
};
}
WeakRef & WeakMap
Use WeakMap and WeakSet to hold references that don't prevent garbage collection:
let obj = { data: "important" };
let weakMap = new WeakMap();
weakMap.set(obj, "metadata");
obj = null; // object can now be garbage collected
// weakMap entry is automatically removed
Key Takeaways
- Primitives go on the stack, objects on the heap.
- JavaScript uses mark-and-sweep garbage collection.
- Memory leaks happen when references to unused data are accidentally kept alive.
- Use
WeakMap/WeakSetfor references that shouldn't prevent GC.