Memory Management in JavaScript

Understanding memory management and garbage collection in JavaScript is crucial for writing performant applications and avoiding memory leaks.

Memory Lifecycle

// 1. Memory Allocation
let number = 123; // allocates memory for a number
let string = "Hello"; // allocates memory for a string
let object = { a: 1 }; // allocates memory for an object
let array = [1, 2, 3]; // allocates memory for an array

// 2. Memory Usage
object.b = 2; // uses previously allocated memory
array.push(4); // might allocate new memory if needed

// 3. Memory Release
object = null; // marks memory available for garbage collection
array = null; // marks array memory for garbage collection

Common Memory Leaks

// 1. Global Variables
function leak() {
  leakedVariable = "I'm leaked"; // accidentally global
}

// 2. Forgotten Timers
function startTimer() {
  const heavyObject = { data: new Array(1000000) };
  setInterval(() => {
    console.log(heavyObject); // heavyObject never garbage collected
  }, 1000);
}

// 3. Closures
function closure() {
  const heavyData = new Array(1000000);
  return function() {
    console.log(heavyData[0]); // heavyData is retained
  };
}

// 4. Event Listeners
function addHandler() {
  const element = document.getElementById('button');
  element.addEventListener('click', () => {
    // Handler retained even if element is removed
    heavyData.process();
  });
}

Preventing Memory Leaks

// 1. Clearing Timers
let timer;
function startTimer() {
  const data = heavyComputation();
  timer = setInterval(() => {
    console.log(data);
  }, 1000);
}

function stopTimer() {
  clearInterval(timer);
  timer = null;
}

// 2. Removing Event Listeners
function setupHandler() {
  const handler = () => {
    // handle event
  };
  element.addEventListener('click', handler);
  
  return () => {
    element.removeEventListener('click', handler);
  };
}

// 3. WeakMap and WeakSet
const cache = new WeakMap();
let object = { data: 'valuable' };
cache.set(object, 'metadata');
object = null; // object and its metadata can be garbage collected

// 4. Proper Closure Management
function createCounter() {
  let count = 0;
  return () => ++count; // only retains what's needed
}

Memory Analysis

// Using Chrome DevTools
// 1. Take heap snapshot
// Chrome DevTools -> Memory -> Take Snapshot

// 2. Record allocation timeline
// Chrome DevTools -> Memory -> Record Allocation Timeline

// 3. Check memory usage
console.log(process.memoryUsage());
/*
{
  heapUsed: 12345678,
  heapTotal: 23456789,
  external: 1234567,
  arrayBuffers: 123456
}
*/

Common Interview Follow-up Questions

  1. How does JavaScript's garbage collection work?
  2. What are the common causes of memory leaks?
  3. How do you identify memory leaks?
  4. What's the difference between WeakMap and Map?

Best Practices

  • Always clean up timers and event listeners
  • Use WeakMap/WeakSet for caching object references
  • Avoid accidental global variables
  • Profile memory usage during development
  • Be careful with closures retaining large objects
  • Implement proper cleanup in SPA routes