READMEJavaScript

README

Module 12 Execution Context / .5 Memory Management

Concept Lesson
Advanced
4 min

Learning Objective

Understand Module 12 Execution Context well enough to explain it, recognize it in JavaScript, and apply it in a small task.

Why It Matters

This concept is part of the foundation that later lessons and projects assume you already understand.

ExecutionContextMemory LifecycleStack Vs Heap MemoryPrimitives Stack
Private notes
0/8000

Notes stay private to your browser until account sync is configured.

README
2 min read18 headings

6.5 Memory Management

Introduction

JavaScript automatically manages memory, but understanding how it works helps you write more efficient code and avoid memory leaks. This section covers memory allocation, garbage collection, and common pitfalls.


Memory Lifecycle

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                  MEMORY LIFECYCLE                       │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                         │
│  1. ALLOCATE                                            │
│     └── JavaScript allocates memory when you create     │
│         variables, objects, functions, etc.             │
│                                                         │
│  2. USE                                                 │
│     └── Read and write to allocated memory              │
│                                                         │
│  3. RELEASE                                             │
│     └── Garbage collector frees memory that is         │
│         no longer needed                                │
│                                                         │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Stack vs Heap Memory

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                   MEMORY MODEL                           │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│       STACK           │           HEAP                   │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                       │                                  │
│  • Primitives         │  • Objects                       │
│  • Function calls     │  • Arrays                        │
│  • Fixed size         │  • Functions                     │
│  • Fast access        │  • Dynamic size                  │
│  • Auto cleanup       │  • GC cleanup                    │
│                       │                                  │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”      │  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    │
│  │  num: 42    │      │  │ { name: "Alice", ... }  │    │
│  ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤      │  ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤    │
│  │  str: "hi"  │──────┼──│ [1, 2, 3, 4, 5]         │    │
│  ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤      │  ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤    │
│  │  ref: ───────┼─────┼──│ function() { ... }      │    │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜      │  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜    │
│                       │                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Primitives (Stack):

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

Objects (Heap):

let obj1 = { x: 10 }; // Object in heap, reference in stack
let obj2 = obj1; // Same reference copied
obj2.x = 20;
console.log(obj1.x); // 20 (same object!)

Garbage Collection

JavaScript uses garbage collection (GC) to automatically free unused memory.

Mark-and-Sweep Algorithm:

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                 MARK AND SWEEP                          │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                         │
│  1. MARK PHASE                                          │
│     • Start from "roots" (global, stack variables)      │
│     • Mark all reachable objects                        │
│                                                         │
│  2. SWEEP PHASE                                         │
│     • Free unmarked (unreachable) objects               │
│                                                         │
│                                                         │
│   ROOT                                                  │
│    ↓                                                    │
│   [A] ──→ [B] ──→ [C]     [D]     [E]                  │
│    ↓       ↓               ↑                            │
│   [F]     [G]             [H]                           │
│                                                         │
│   Reachable: A, B, C, F, G (marked āœ“)                   │
│   Unreachable: D, E, H (swept away)                     │
│                                                         │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

What Makes Something "Reachable"?

  1. Global variables (always reachable)
  2. Currently executing function's local variables
  3. Closure variables
  4. Objects referenced by reachable objects

Memory Leaks

A memory leak occurs when memory that is no longer needed is not released.

Common Causes:

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│              COMMON MEMORY LEAKS                        │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                         │
│  1. Accidental globals                                  │
│  2. Forgotten timers/callbacks                          │
│  3. Detached DOM nodes                                  │
│  4. Closures holding references                         │
│  5. Event listeners not removed                         │
│                                                         │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Leak 1: Accidental Globals

// BAD: Creates global variable (no var/let/const)
function leak() {
  accidentalGlobal = "I'm global!"; // Oops!
}
leak();
// accidentalGlobal stays in memory forever

// GOOD: Use strict mode
function noLeak() {
  'use strict';
  accidentalGlobal = 'Error!'; // ReferenceError!
}

Leak 2: Forgotten Timers

// BAD: Timer keeps running, keeps reference to data
function startPolling() {
  const largeData = new Array(1000000).fill('data');

  setInterval(() => {
    console.log(largeData.length); // Keeps largeData alive!
  }, 1000);
}

// GOOD: Clear timers when done
function startPollingGood() {
  const largeData = new Array(1000000).fill('data');

  const timerId = setInterval(() => {
    console.log(largeData.length);
  }, 1000);

  // Later, when done:
  // clearInterval(timerId);
  return timerId; // Allow cleanup
}

Leak 3: Detached DOM Nodes

// BAD: Removed from DOM but still referenced
let detachedElement;

function createLeak() {
  const element = document.createElement('div');
  document.body.appendChild(element);
  detachedElement = element; // Keep reference
  document.body.removeChild(element); // Removed from DOM
  // Element still in memory because detachedElement holds it!
}

// GOOD: Clear references
function createNoLeak() {
  const element = document.createElement('div');
  document.body.appendChild(element);
  document.body.removeChild(element);
  // No reference kept, element can be garbage collected
}

Leak 4: Closures

// POTENTIAL LEAK: Closure keeps reference to large object
function createClosure() {
  const largeArray = new Array(1000000).fill('x');

  return function () {
    // This closure keeps largeArray in memory!
    console.log(largeArray.length);
  };
}

const leakyFunction = createClosure();
// largeArray stays in memory as long as leakyFunction exists

// BETTER: Only keep what you need
function createBetterClosure() {
  const largeArray = new Array(1000000).fill('x');
  const length = largeArray.length; // Extract needed value

  return function () {
    console.log(length); // Only keeps the number
  };
}

Leak 5: Event Listeners

// BAD: Listeners not removed
class LeakyComponent {
  constructor() {
    this.data = new Array(10000).fill('x');
    window.addEventListener('resize', this.handleResize);
  }

  handleResize = () => {
    console.log(this.data.length);
  };

  // Missing cleanup!
}

// GOOD: Remove listeners on cleanup
class GoodComponent {
  constructor() {
    this.data = new Array(10000).fill('x');
    this.handleResize = this.handleResize.bind(this);
    window.addEventListener('resize', this.handleResize);
  }

  handleResize() {
    console.log(this.data.length);
  }

  destroy() {
    window.removeEventListener('resize', this.handleResize);
  }
}

Debugging Memory Issues

Chrome DevTools:

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│               MEMORY DEBUGGING TOOLS                    │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                         │
│  1. Memory Tab                                          │
│     • Heap snapshots                                    │
│     • Allocation timelines                              │
│     • Allocation sampling                               │
│                                                         │
│  2. Performance Tab                                     │
│     • Memory graph over time                            │
│     • Identify growing memory                           │
│                                                         │
│  3. Task Manager (Chrome)                               │
│     • Shift+Esc                                         │
│     • See JS memory per tab                             │
│                                                         │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Heap Snapshot Steps:

  1. Open DevTools → Memory tab
  2. Take "Heap snapshot"
  3. Perform actions that might leak
  4. Take another snapshot
  5. Compare snapshots to find growth

WeakMap and WeakSet

These collections allow garbage collection of their keys:

// Regular Map - prevents garbage collection
const cache = new Map();

let obj = { data: 'important' };
cache.set(obj, 'cached value');

obj = null; // Object still in memory (Map holds it)!

// WeakMap - allows garbage collection
const weakCache = new WeakMap();

let obj2 = { data: 'important' };
weakCache.set(obj2, 'cached value');

obj2 = null; // Object can be garbage collected!

When to Use:

// Good use case: Associating data with DOM elements
const elementData = new WeakMap();

function processElement(element) {
  if (!elementData.has(element)) {
    elementData.set(element, { processed: true });
  }
  return elementData.get(element);
}
// When element is removed from DOM and all references cleared,
// the associated data is also garbage collected

Memory Optimization Patterns

1. Object Pooling

// Instead of creating/destroying many objects:
class BulletPool {
  constructor(size) {
    this.pool = Array.from({ length: size }, () => ({
      x: 0,
      y: 0,
      active: false,
    }));
  }

  acquire() {
    const bullet = this.pool.find((b) => !b.active);
    if (bullet) bullet.active = true;
    return bullet;
  }

  release(bullet) {
    bullet.active = false;
    bullet.x = 0;
    bullet.y = 0;
  }
}

2. Lazy Loading

// Don't load everything upfront
let heavyModule = null;

async function getHeavyModule() {
  if (!heavyModule) {
    heavyModule = await import('./heavyModule.js');
  }
  return heavyModule;
}

3. Chunked Processing

// Process large arrays in chunks to avoid memory spikes
async function processLargeArray(items, chunkSize = 1000) {
  const results = [];

  for (let i = 0; i < items.length; i += chunkSize) {
    const chunk = items.slice(i, i + chunkSize);
    const processed = await processChunk(chunk);
    results.push(...processed);

    // Allow GC between chunks
    await new Promise((r) => setTimeout(r, 0));
  }

  return results;
}

Summary

ConceptDescription
StackFast, fixed-size memory for primitives
HeapDynamic memory for objects
Garbage CollectionAutomatic memory cleanup
Mark and SweepGC algorithm - marks reachable, sweeps rest
Memory LeakMemory not released when no longer needed
WeakMap/WeakSetCollections that allow GC of keys
Object PoolingReuse objects instead of creating new ones

Best Practices

  1. Use const and let - Avoid accidental globals
  2. Clear timers and intervals - clearTimeout, clearInterval
  3. Remove event listeners - Especially on dynamic elements
  4. Avoid large closures - Only capture what's needed
  5. Nullify references - Set to null when done with large objects
  6. Use WeakMap/WeakSet - For metadata attached to objects
  7. Profile regularly - Use DevTools Memory tab

Module 6 Complete!

You now understand:

  • Execution contexts and how code runs
  • The call stack and function execution
  • Hoisting behavior for different declarations
  • The event loop and async execution
  • Memory management and garbage collection

These concepts are fundamental to writing efficient, bug-free JavaScript!

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue