Memory Management
How JavaScript allocates, uses, and frees memory automatically.
Memory Lifecycle
Three stages: allocate → use → release.
1. Allocate
Reserve memory
2. Use
Read / Write
3. Release
Free memory
// 1. Allocate:
const name = "Alice"; // allocates memory for string
const nums = [1, 2, 3]; // allocates memory for array
const user = { age: 28 }; // allocates memory for object
// 2. Use:
console.log(name); // reads from memory
nums.push(4); // writes to memory
// 3. Release:
// JavaScript does this AUTOMATICALLY
// via Garbage Collection (GC)
// You don't call free() or delete manuallyStack vs Heap
Two types of memory with different purposes.
Stack Memory
- • Primitives (numbers, strings, booleans)
- • Function call frames
- • References (pointers to heap)
- • Fixed size, fast access
- • Auto-freed when scope ends
Heap Memory
- • Objects, arrays, functions
- • Dynamic size
- • Slower access than stack
- • Freed by Garbage Collector
- • Can grow as needed
let age = 28; // stack: stores 28 directly
let name = "Alice"; // stack: reference → heap: "Alice"
let user = { age: 28 }; // stack: reference → heap: { age: 28 }
let arr = [1, 2, 3]; // stack: reference → heap: [1, 2, 3]
// When variables go out of scope:
// Stack values are immediately freed
// Heap values wait for garbage collectionGarbage Collection
The engine automatically frees unreachable memory.
// Mark-and-Sweep algorithm:
// 1. Start from "roots" (global, stack variables)
// 2. Mark all objects reachable from roots
// 3. Sweep (free) all unmarked objects
let user = { name: "Alice" }; // reachable ✓
user = null; // { name: "Alice" } is now unreachable
// GC will free it on next cycleThe main algorithm: if no live variable can reach an object, it's garbage and gets freed.
💡 Unreachable = eligible for collection
1 / 3
Memory Leaks
When memory can't be freed because references accidentally persist.
1. Forgotten event listeners
// Leak: listener holds reference to large data
function setup() {
const hugeData = new Array(1000000);
element.addEventListener("click", () => {
console.log(hugeData.length); // holds hugeData!
});
}
// Fix: remove listener when done
// element.removeEventListener("click", handler);2. Global variables
// Leak: accidentally creating globals
function process() {
result = data.map(x => x * 2); // missing 'const'!
// 'result' is now global and never freed
}
// Fix: always use const/let3. Detached DOM nodes
// Leak: reference to removed DOM element
const button = document.getElementById("btn");
button.remove(); // removed from DOM
// But 'button' variable still holds a reference!
// The DOM node can't be GC'd
// Fix: button = null;4. Closures holding large data
function createHandler() {
const bigArray = new Array(1000000).fill("x");
return () => {
// Only uses bigArray.length but holds ALL of it
return bigArray.length;
};
}
// Fix: extract what you need before closure
// const len = bigArray.length;
// return () => len;Best Practices
Write memory-efficient JavaScript.
✓Use const/let, never implicit globals
✓Remove event listeners when components unmount
✓Nullify references to large objects when done
✓Use WeakMap/WeakSet for caches (allow GC)
✓Clear intervals/timeouts when no longer needed
✓Avoid storing unnecessary data in closures
FAQ
Common questions about memory.