Hack Frontend Community

How to Debug Application and Find Memory Leaks

General Debugging Process

1

Identify problem

  • Application freezes, slows down or consumes too much memory?
  • Use browser tools: DevTools (Performance, Memory), Console, React Profiler.
2

Log and error analysis

  • Add console.log, console.trace, console.error for tracking.
  • Use external tools: Sentry, LogRocket, Datadog for error logging.
3

Performance profiling

  • Performance tab in Chrome DevTools — analyze FPS, load and render time.
  • React Profiler — identify unnecessary re-renders.
  • Lighthouse — optimization recommendations.
4

Memory leak analysis

  • Use Memory tab and Heap Snapshot.
  • Look for objects that aren't deleted after component unmounting.
  • Watch for setInterval, setTimeout, WebSocket, EventListeners.

Memory Leak Causes and Solutions

Forgotten Timers and Intervals

useEffect(() => {
  const interval = setInterval(() => console.log("tick"), 1000);
  return () => clearInterval(interval); // must clean up!
}, []);

Unremoved Event Handlers

useEffect(() => {
  const handleScroll = () => console.log("scrolling...");
  window.addEventListener("scroll", handleScroll);
  return () => window.removeEventListener("scroll", handleScroll);
}, []);

Closures Holding Data

Closures can "remember" references to objects, and they won't be deleted. Solution: use useRef, useCallback or clean up in time.

Global Variables

window.myCache = largeObject; // bad practice

// better explicitly clean
window.myCache = null;

References in useRef and DOM

const ref = useRef(null);

useEffect(() => {
  ref.current = document.getElementById("my-element");

  return () => {
    ref.current = null; // release reference
  };
}, []);

WebSocket or Subscriptions Not Closed in Time

useEffect(() => {
  const socket = new WebSocket("wss://example.com");
  return () => socket.close(); // must close
}, []);

Lack of Virtualization on Large Lists

Rendering 1000+ elements without virtualization slows application and "clogs" memory.

Solution: use libraries:

How to Find Memory Leaks

Memory Tab → Heap Snapshot

  • Go to DevTools → Memory → Take Snapshot
  • Interact with component (e.g., open/close modal)
  • Take another Snapshot
  • Compare: temporary objects should disappear

Performance Tab → Record Allocations

  • Click "Start recording allocations"
  • Use component
  • Click "Stop" and look for leaks that remain after component removal

Monitoring Tools

  • Chrome DevTools — built-in memory analyzer and profiler
  • Sentry, Datadog, LogRocket — detecting and logging leaks and errors in production
  • why-did-you-render — helps find unnecessary component re-renders

Important:

Memory leaks are especially dangerous in SPA (Single Page Application), as application lives long. Even small leaks can lead to performance degradation over time.

Conclusion

  • Watch for side-effect cleanup (setInterval, event listeners, sockets)
  • Use DevToolsMemorySnapshot for diagnostics
  • Don't store global objects or closures that aren't cleaned
  • For large lists — apply virtualization
  • Use React Profiler and browser profiling to find bottlenecks
// Example of safe useEffect pattern
useEffect(() => {
  const res = startSomething();
  return () => {
    cleanupSomething(res);
  };
}, []);