JavaScript Memory Leak Issues
What This Means
Memory leaks occur when JavaScript applications retain references to objects that are no longer needed, preventing the garbage collector from freeing memory. Over time, this causes:
- Increasing memory usage that never gets released
- Page slowdown and degraded performance
- Browser tab crashes from out-of-memory errors
- Reduced battery life on mobile devices
- Poor user experience in single-page applications (SPAs)
Common causes of memory leaks:
- Forgotten event listeners not removed on cleanup
- Detached DOM nodes still referenced in JavaScript
- Global variables accumulating data
- Closures capturing large objects
- Timers and intervals not cleared
- Circular references preventing garbage collection
How to Diagnose
Chrome DevTools Memory Panel
- Take heap snapshots before and after using features
- Compare snapshots to find retained objects
- Use Allocation Timeline to track memory over time
- Record Allocation Instrumentation to find allocation sources
Memory Profiling Steps
// Monitor memory usage
if (performance.memory) {
console.log('Used JS Heap Size:',
(performance.memory.usedJSHeapSize / 1048576).toFixed(2) + ' MB');
console.log('Total JS Heap Size:',
(performance.memory.totalJSHeapSize / 1048576).toFixed(2) + ' MB');
}
Common Leak Patterns
- Memory consistently increasing over time
- Detached DOM tree count growing
- Event listener count increasing
- Large arrays or objects never released
Task Manager
- Chrome: Shift+Esc to open Task Manager
- Monitor JavaScript Memory column
- Look for continuous growth without stabilization
General Fixes
Remove event listeners on cleanup
// Bad element.addEventListener('click', handler); // Good useEffect(() => { element.addEventListener('click', handler); return () => element.removeEventListener('click', handler); }, []);Clear timers and intervals
const timerId = setInterval(callback, 1000); // Later... clearInterval(timerId);Avoid global variables - Use modules and local scope to limit lifetime
WeakMap/WeakSet for caches - Allow garbage collection of keys
// Good for caching DOM elements const cache = new WeakMap(); cache.set(element, data);Nullify large object references - Explicitly set to null when done
let largeObject = /* ... */; // Use largeObject... largeObject = null; // Allow GCUnsubscribe from observables - Clean up RxJS, Redux subscriptions
const subscription = observable.subscribe(handler); subscription.unsubscribe();Use AbortController for fetch - Cancel and clean up requests
const controller = new AbortController(); fetch(url, { signal: controller.signal }); controller.abort(); // Clean upAvoid detached DOM nodes - Remove all references when removing elements
Implement proper React cleanup - Return cleanup functions from useEffect
Platform-Specific Guides
| Platform | Guide |
|---|---|
| React | Memory Leaks in React |
| Angular | Unsubscribe Pattern |
| Vue | Lifecycle Cleanup |
| Redux | Unsubscribe from Store |