Docs

README

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!

README - JavaScript Tutorial | DeepML