When your Node.js app crashes on high memory usage, especially in production, it usually points to a memory leak or unoptimized resource handling.
Here’s how to debug it step by step 👇
🧠 1. Check Logs and Resource Metrics First
Start by checking logs, monitoring dashboards, and system metrics.
- Use
toporhtopto see if the process memory spikes. - Check container or server logs for “out of memory” (OOM) errors.
- Use APM tools like New Relic, Datadog, or built-in logs to trace the pattern.
✅ This helps confirm whether the crash is due to memory or something else.
🧠 2. Enable Node.js Memory Heap Snapshots
Run the app with the --inspect flag or use the Chrome DevTools to inspect memory in real time.
node --inspect index.js
Then open: chrome://inspect → “Memory” tab → take a Heap Snapshot.
This shows which objects are taking memory and not getting garbage collected.
✅ If you see certain objects growing over time, that’s your leak.
🧠 3. Monitor Memory Usage in Code
Use process.memoryUsage() to log memory usage at intervals.
setInterval(() => {
const mem = process.memoryUsage();
console.log(`Heap Used: ${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB`);
}, 5000);
✅ If heap usage continuously grows and never drops, you likely have a memory leak.
🧠 4. Analyze Code for Common Leak Patterns
Memory leaks often come from:
- Unclosed database connections
- Unbounded arrays or objects storing large data
- Event listeners not removed properly
- Global variables growing over time
- Long-lived promises or timers
👉 Example of a leak:
let cache = [];
app.get("/leak", (req, res) => {
cache.push(new Array(1000000).fill("data")); // never cleared!
res.send("OK");
});
✅ Fix by cleaning or limiting stored data:
cache = [];
🧠 5. Use Profiling Tools in Production Safely
For deeper analysis, use tools like:
- clinic.js
- 0x
- heapdump
Example with heapdump:
import heapdump from "heapdump";
process.on("SIGUSR2", () => {
const file = `/tmp/heap-${Date.now()}.heapsnapshot`;
heapdump.writeSnapshot(file);
console.log(`Heap snapshot written to ${file}`);
});
✅ You can analyze these snapshots in Chrome DevTools even after the crash.
🧠 6. Set Memory Limits and Graceful Restarts
Even after fixing leaks, use tools like PM2 to gracefully handle spikes.
pm2 start index.js --max-memory-restart 500M
✅ This prevents the entire app from crashing and restarts it gracefully.
🧠 7. Optimize Upstream Dependencies
Sometimes the leak isn’t in your code but in a dependency or an upstream service not closing connections.
- Upgrade outdated packages.
- Check for open streams, sockets, or file handles.
- Use proper cleanup in
finallyblocks.
✅ In short:
- Reproduce the issue and confirm memory spikes.
- Take heap snapshots and monitor memory usage.
- Identify and fix leaks in code or dependencies.
- Use profiling tools to dig deeper.
- Add safe guards like memory limits and restarts.
👉 This step-by-step approach helps diagnose and fix memory issues without shooting in the dark.