debugjavascriptMajorpending
Debug: Memory leak in single-page applications
Viewed 0 times
memory-leakSPAevent-listenercleanupuseEffectheap
Error Messages
Problem
Single-page application memory usage grows over time as users navigate, eventually becoming slow or crashing.
Solution
Common SPA memory leaks and fixes:
// BAD:
useEffect(() => {
window.addEventListener('resize', handler);
}, []);
// GOOD:
useEffect(() => {
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
useEffect(() => {
const id = setInterval(poll, 5000);
return () => clearInterval(id);
}, []);
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal }).then(...);
return () => controller.abort();
}, [url]);
// Closure captures large data that's no longer needed
// Fix: null out references when done
// Saving references to removed elements
// Check: DevTools > Memory > Heap Snapshot > Detached
// Add eviction: LRU cache, max size, TTL
useEffect(() => {
const ws = new WebSocket(url);
return () => ws.close();
}, []);
Debug tools:
- Event listeners not cleaned up:
// BAD:
useEffect(() => {
window.addEventListener('resize', handler);
}, []);
// GOOD:
useEffect(() => {
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
- Timers not cleared:
useEffect(() => {
const id = setInterval(poll, 5000);
return () => clearInterval(id);
}, []);
- AbortController for abandoned requests:
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal }).then(...);
return () => controller.abort();
}, [url]);
- Closures holding references:
// Closure captures large data that's no longer needed
// Fix: null out references when done
- Detached DOM nodes:
// Saving references to removed elements
// Check: DevTools > Memory > Heap Snapshot > Detached
- Growing arrays/maps used as caches:
// Add eviction: LRU cache, max size, TTL
- WebSocket/SSE connections not closed:
useEffect(() => {
const ws = new WebSocket(url);
return () => ws.close();
}, []);
Debug tools:
- Chrome DevTools > Memory > Take heap snapshot
- Compare snapshots to find growing objects
- Performance Monitor > JS Heap Size
Revisions (0)
No revisions yet.