JavaScript Memory Leak Issues | Blue Frog Docs

JavaScript Memory Leak Issues

Understanding and fixing JavaScript memory leaks affecting performance and stability

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

  1. Take heap snapshots before and after using features
  2. Compare snapshots to find retained objects
  3. Use Allocation Timeline to track memory over time
  4. 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

  1. Remove event listeners on cleanup

    // Bad
    element.addEventListener('click', handler);
    
    // Good
    useEffect(() => {
      element.addEventListener('click', handler);
      return () => element.removeEventListener('click', handler);
    }, []);
    
  2. Clear timers and intervals

    const timerId = setInterval(callback, 1000);
    // Later...
    clearInterval(timerId);
    
  3. Avoid global variables - Use modules and local scope to limit lifetime

  4. WeakMap/WeakSet for caches - Allow garbage collection of keys

    // Good for caching DOM elements
    const cache = new WeakMap();
    cache.set(element, data);
    
  5. Nullify large object references - Explicitly set to null when done

    let largeObject = /* ... */;
    // Use largeObject...
    largeObject = null; // Allow GC
    
  6. Unsubscribe from observables - Clean up RxJS, Redux subscriptions

    const subscription = observable.subscribe(handler);
    subscription.unsubscribe();
    
  7. Use AbortController for fetch - Cancel and clean up requests

    const controller = new AbortController();
    fetch(url, { signal: controller.signal });
    controller.abort(); // Clean up
    
  8. Avoid detached DOM nodes - Remove all references when removing elements

  9. 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

Further Reading

// SYS.FOOTER