Memory Management
JavaScript manages memory automatically through garbage collection (GC). Developers don’t allocate or free memory manually, but must avoid patterns that prevent GC from reclaiming unused objects.
Memory Lifecycle
- Allocate — memory assigned when creating values
- Use — read and write values
- Release — garbage collector frees unreachable memory
Reachability
An object is kept in memory if it is reachable from a root (global object, current call stack, closures):
let user = { name: 'Alice' };
user = null; // previous object may be collected if nothing else references it
Garbage Collection Algorithms
Modern engines (V8, SpiderMonkey) use generational GC:
- Young generation — new objects, frequent fast collections
- Old generation — long-lived objects, less frequent full collections
Mark-and-sweep: mark all reachable objects from roots, sweep unreachable ones.
Common Memory Leaks
1. Global variables
function leak() {
accidentalGlobal = 'oops'; // becomes window.accidentalGlobal
}
Fix: "use strict" or always declare with let/const.
2. Forgotten timers
const id = setInterval(() => {
// holds reference to large data
}, 1000);
// Fix: clearInterval(id) when done
3. Detached DOM nodes
let element = document.querySelector('#big-list');
document.body.removeChild(element);
// element still referenced in JS — DOM tree kept in memory
element = null; // allow GC
4. Closures holding large data
function createHandler() {
const hugeData = new Array(1e6).fill('x');
return function() {
console.log(hugeData.length); // hugeData never collected
};
}
Fix: only close over what you need:
function createHandler() {
const hugeData = new Array(1e6).fill('x');
const size = hugeData.length;
return function() {
console.log(size);
};
}
5. Event listeners not removed
Always remove listeners when components are destroyed (SPA route changes, modal close).
WeakMap and WeakSet
Allow GC of keys when no other references exist:
const privateData = new WeakMap();
class User {
constructor(name) {
privateData.set(this, { name });
}
getName() {
return privateData.get(this).name;
}
}
// When User instance is unreachable, WeakMap entry is collected
FinalizationRegistry (Advanced)
Run cleanup when object is garbage-collected:
const registry = new FinalizationRegistry((heldValue) => {
console.log('Cleaned up:', heldValue);
});
let obj = { id: 1 };
registry.register(obj, 'resource-1');
obj = null; // eventually triggers cleanup callback
Monitoring Memory
Chrome DevTools → Memory tab:
- Heap snapshot — see what objects exist
- Allocation timeline — track allocations over time
Node.js:
console.log(process.memoryUsage());
// { rss, heapTotal, heapUsed, external, arrayBuffers }
Best Practices
- Null out references when done with large objects
- Use
WeakMap/WeakSetfor caches keyed by objects - Clear intervals/timeouts and remove event listeners
- Avoid storing DOM references longer than needed
- Profile memory in long-running apps (SPAs, Node servers)
Understanding memory helps you build applications that stay fast and stable over time.