Loading...
Loading...
How JavaScript allocates, uses, and frees memory automatically.
Module 6 · How JavaScript Works
Understanding the engine makes you a better debugger. Execution contexts, the call stack, hoisting, memory allocation, closures, and the prototype chain explain why JavaScript behaves the way it does under the hood.
JavaScript allocates memory automatically and reclaims unreachable objects via garbage collection — but lingering references can still leak memory in long-lived single-page apps.
JavaScript looks simple on the surface, but the engine does a lot of work behind the scenes. Variables are hoisted, functions create new execution contexts, the call stack tracks nested calls, and the prototype chain resolves property lookups.
This module is for developers who want to stop guessing and start understanding. Visual diagrams of the call stack, heap, and scope chain make abstract concepts concrete — and directly improve your debugging skills in real projects.
Memory leaks make tabs slower over hours and crash mobile browsers. Knowing stack versus heap, reachability, and common leak patterns separates engineers who can debug production issues from those who cannot.
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 manually
Two types of memory with different purposes.
Stack Memory
Heap Memory
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 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 cycle
The main algorithm: if no live variable can reach an object, it's garbage and gets freed.
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/let
3. 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;
Write memory-efficient JavaScript.
Common questions about memory management.