Page cover
Memory leaks hide in plain sight - learn to spot them, measure them, and eliminate them before they impact users.

How to Debug Memory Leaks in React Applications

Debugging Advanced 45-60 minutes December 15, 2024

Identify and fix memory leaks in your React applications using Chrome DevTools and best practices.

Things You'll Need

  • React application with suspected memory leak
  • Chrome browser with DevTools
  • Basic understanding of React hooks and lifecycle

Steps

Follow these 8 steps to complete this guide

1

Identify Memory Leak Symptoms

Watch for signs like gradually increasing memory usage, slow performance over time, or browser tab crashes. Open Chrome DevTools and monitor the Memory tab while using your app.

Tips

  • Memory leaks are often noticed in long-running applications
  • Look for memory usage that keeps increasing and never decreases
2

Take Heap Snapshots

Use Chrome DevTools to take heap snapshots at different points in your app's lifecycle. Compare snapshots to identify objects that aren't being garbage collected.

text
1. Open Chrome DevTools (F12)
2. Go to Memory tab
3. Select "Heap snapshot"
4. Click "Take snapshot"
5. Interact with your app
6. Take another snapshot
7. Compare snapshots to find retained objects

Tips

  • Take snapshots after performing the same action multiple times
  • Look for objects with increasing counts between snapshots
3

Check for Cleanup in useEffect

The most common cause of memory leaks in React is forgetting to clean up subscriptions, timers, and event listeners in useEffect.

typescript
// BAD - Memory leak!
useEffect(() => {
  const interval = setInterval(() => {
    console.log('Running...');
  }, 1000);
  // Missing cleanup!
}, []);

// GOOD - Properly cleaned up
useEffect(() => {
  const interval = setInterval(() => {
    console.log('Running...');
  }, 1000);

  return () => {
    clearInterval(interval); // Cleanup on unmount
  };
}, []);

Warnings

  • Always return a cleanup function from useEffect when using subscriptions or timers
4

Fix Event Listener Leaks

Event listeners attached to window or document must be removed when the component unmounts.

typescript
// BAD
useEffect(() => {
  window.addEventListener('resize', handleResize);
}, []);

// GOOD
useEffect(() => {
  const handleResize = () => {
    // handle resize
  };

  window.addEventListener('resize', handleResize);

  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []);
5

Handle setState After Unmount

Calling setState on an unmounted component is a common source of memory leaks and warnings. Use cleanup flags to prevent this.

typescript
function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    let isMounted = true;

    fetch('/api/data')
      .then(res => res.json())
      .then(data => {
        if (isMounted) {
          setData(data);
        }
      });

    return () => {
      isMounted = false;
    };
  }, []);

  return <div>{data}</div>;
}

Tips

  • Use AbortController for fetch requests to cancel them on unmount
  • Consider using libraries like react-query that handle this automatically
6

Use the Performance Profiler

React DevTools Profiler can help identify components that re-render unnecessarily, which can contribute to memory issues.

text
1. Install React DevTools extension
2. Open DevTools > Profiler tab
3. Click record
4. Interact with your app
5. Stop recording
6. Analyze which components render and why
7

Fix Closure Traps

Be careful with closures in useEffect and useCallback that capture old values or large objects.

typescript
// BAD - Captures entire data object
const handleClick = useCallback(() => {
  console.log(data.value);
}, []); // Empty deps, but uses data

// GOOD - Properly specified dependencies
const handleClick = useCallback(() => {
  console.log(data.value);
}, [data.value]); // Only captures what's needed

Warnings

  • Missing dependencies in useCallback/useMemo can cause stale closures
8

Test and Verify the Fix

After fixing potential leaks, take new heap snapshots and verify memory is being released properly.

Tips

  • Mount and unmount the component multiple times
  • Check if memory returns to baseline after unmounting
  • Use the Memory tab's timeline view to visualize memory over time
Tags: React Performance Memory Leaks Debugging

Was this guide helpful?

Check out more step-by-step guides for development, deployment, debugging, and configuration.