JavaScript Memory Management
How allocation, garbage collection, and leaks work in JavaScript
Overview
JavaScript allocates memory automatically when you create values and frees it with a garbage collector. The collector uses reachability: any value reachable from a root (globals, the call stack, active closures) is kept, and everything else is eligible for collection. Memory leaks happen when references linger longer than needed.
Syntax / Usage
You rarely manage memory manually, but you control reachability by holding or dropping references. WeakMap, WeakSet, and WeakRef let you reference objects without preventing their collection.
let cache = new Map()
cache.set('user:1', { name: 'Ada' }) // strong reference, stays alive
// A WeakMap does not keep its keys alive
const meta = new WeakMap()
let node = { id: 1 }
meta.set(node, { visited: true })
node = null // the object (and its WeakMap entry) can now be collected
Examples
Closures keep referenced variables alive—retain only what you need:
function createCounter() {
let count = 0 // captured by the returned closure, stays in memory
return () => ++count
}
const next = createCounter()
console.log(next(), next()) // 1 2
A detached DOM reference is a classic leak; clearing it lets memory free up:
let detached = []
function leak() {
const el = document.createElement('div')
detached.push(el) // array keeps every element reachable forever
}
function cleanup() {
detached = [] // drop references so the collector can reclaim them
}
Forgotten timers hold their callbacks (and captured scope) alive:
function startPolling(getData) {
const id = setInterval(() => getData(), 1000)
return () => clearInterval(id) // return a disposer to stop the leak
}
const stop = startPolling(() => {})
stop() // without this, the interval and closure live forever
Common Mistakes
- Accumulating entries in a long-lived
Mapor array without ever removing them - Forgetting to
clearInterval/clearTimeoutor remove event listeners - Holding large objects in closures that outlive their usefulness
- Assuming setting a variable to
nullfrees memory when other references still exist - Using
MapwhereWeakMapis appropriate, preventing key objects from being collected
See Also
closures objects javascript-event-loop