Dev
Memory Leaks in JavaScript
Memory leaks occur when unused memory is not released, degrading application performance.
Common Causes and solutions
1. Unintentional Global Variables
Cause : Variables declared without var, let, or const become global.
function createLeak() {
leakedVar = 'This is a global variable'; // Global scope
}
Solution : Use strict mode or explicit declarations:
"use strict";
function preventLeak() {
let safeVar = 'Local variable'; // Block-scoped
}
2. Closures Retaining References
Cause : Closures retain outer scope variables unnecessarily.
function outer() {
const largeData = new Array(1000000).fill('data');
return function inner() {
console.log('Closure retains largeData'); // largeData is not GC'd
};
}
Solution : Nullify references after use:
function outer() {
let largeData = new Array(1000000).fill('data');
return function inner() {
console.log('Closure');
largeData = null; // Release reference
};
}
3. Timers and Callbacks
Cause : Uncleared setInterval or event listeners.
const intervalId = setInterval(() => {
// Repeated logic retains references
}, 1000);
// Never cleared → memory leak
Solution : Clean up timers/listeners:
const intervalId = setInterval(...);
clearInterval(intervalId); // Manually clear
// Event listener cleanup:
element.addEventListener('click', handler);
element.removeEventListener('click', handler);
4. Detached DOM Trees
Cause : Removed DOM nodes referenced by JavaScript.
let detachedElement = document.createElement('div');
document.body.appendChild(detachedElement);
document.body.removeChild(detachedElement); // DOM removed
// detachedElement still references the node → not garbage collected
Solution : Nullify references:
detachedElement = null; // Allow GC to reclaim memory
5. Cached Data Accumulation
Cause : Unbounded caches grow indefinitely.
const cache = new Map();
function storeData(key, data) {
cache.set(key, data); // No size limit → leaks over time
}
Solution : Use WeakMap or limit cache size:
const weakCache = new WeakMap(); // Entries GC'd if keys are unreachable
function storeEphemeralData(key, data) {
weakCache.set(key, data);
}
// Or enforce size limits:
const MAX_CACHE_SIZE = 100;
function storeLimitedData(key, data) {
if (cache.size >= MAX_CACHE_SIZE) cache.delete(oldestKey);
cache.set(key, data);
}
Best Practices with Code Examples
- Framework Cleanup (React):
useEffect(() => {
const subscription = dataStream.subscribe();
return () => subscription.unsubscribe(); // Cleanup on unmount
}, []);
- Weak References:
const weakMap = new WeakMap();
const key = { id: 1 };
weakMap.set(key, 'data'); // Entry removed if key is GC'd
- Heap Profiling: Use Chrome DevTools Memory tab to snapshot and compare heap allocations.