Memory Model

Med

JavaScript uses two memory regions: the Stack for primitives and function calls, and the Heap for objects and dynamic data. Understanding this helps you predict performance, avoid memory leaks, and understand how garbage collection works.

Interactive Visualization

Code
1// Primitives (stored in Stack)
2let a = 10;
3let b = a;
4b = 20;
5
6// Objects (stored in Heap)
7let obj1 = { x: 1 };
8let obj2 = obj1;
9obj2.x = 99;
10
11console.log(a, obj1.x);
Stack
(empty)
Heap
(empty)
Script starts. Stack is empty.
1 / 8
Key Insight: Primitives are copied by VALUE (independent). Objects are copied by REFERENCE (shared)!

Key Points

  • Stack: stores primitives (numbers, booleans, strings) and function call frames
  • Heap: stores objects, arrays, and functions (dynamic allocation)
  • Variables hold references (pointers) to heap objects, not the objects themselves
  • Garbage Collection: V8 uses mark-and-sweep to free unreachable objects
  • Memory leaks occur when objects remain referenced but are no longer needed

Code Examples

Primitives vs Objects

// Primitives stored in stack
let a = 10;
let b = a;    // Copy of value
b = 20;
console.log(a);  // 10 (unchanged)

// Objects stored in heap
let obj1 = { x: 1 };
let obj2 = obj1;  // Copy of reference
obj2.x = 99;
console.log(obj1.x);  // 99 (same object!)

Primitives are copied by value, objects by reference

Stack Frames

function outer() {
  let x = 1;  // Frame 1
  inner();
}

function inner() {
  let y = 2;  // Frame 2
  // Stack: [global, outer, inner]
}

outer();
// inner() returns → frame popped
// outer() returns → frame popped

Each function call creates a stack frame

Heap Allocation

// Each {} creates new heap object
function createUser(name) {
  return {
    name: name,
    data: new Array(1000)
  };
}

let user1 = createUser("Alice");
let user2 = createUser("Bob");
// Two separate objects on heap

Objects allocated on heap persist until GC

Garbage Collection

let obj = { data: "important" };

// obj is reachable → NOT collected

obj = null;

// Original object now unreachable
// GC will reclaim this memory
// in next collection cycle

Unreachable objects are garbage collected

Memory Leak

const cache = [];

function processData(data) {
  // BUG: cache grows forever!
  cache.push(data);
  return data.value * 2;
}

// Fix: limit cache size or use WeakMap
const weakCache = new WeakMap();

Unbounded caches cause memory leaks

Closures & Memory

function createCounter() {
  let count = 0;  // Kept alive by closure

  return () => ++count;
}

const counter = createCounter();
// 'count' lives in heap as long
// as 'counter' function exists

Closures keep variables alive on heap

Common Mistakes

  • Thinking primitives and objects are stored the same way
  • Forgetting that object assignment copies references, not values
  • Creating memory leaks with event listeners, closures, or global caches
  • Not understanding that garbage collection is non-deterministic

Interview Tips

  • Draw stack and heap diagrams for given code
  • Explain why === behaves differently for primitives vs objects
  • Know common memory leak patterns and how to fix them
  • Understand WeakMap/WeakSet for cache scenarios

Related Concepts