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.errorfor tracking. - Use external tools: Sentry, LogRocket, Datadog for error logging.
3
Performance profiling
Performancetab in Chrome DevTools — analyze FPS, load and render time.React Profiler— identify unnecessary re-renders.Lighthouse— optimization recommendations.
4
Memory leak analysis
- Use
Memorytab 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,useCallbackor 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 DevTools → Memory → Snapshot 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);
};
}, []);