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 collectionCommon 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
- How does JavaScript's garbage collection work?
- What are the common causes of memory leaks?
- How do you identify memory leaks?
- 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