Node.js 效能分析:偵測 Memory Leak 與 CPU 瓶頸
Node.js 以其卓越的非阻塞 I/O 著稱,但不良的程式慣例仍會導致 記憶體洩漏 (Memory Leak) 或 CPU 密集型阻塞,進而讓伺服器回應變慢、佔用率飆升甚至因 OOM (Out of Memory) 崩潰。
什麼是 Memory Leak?
當你分配了記憶體但不再需要它,而垃圾回收機制 (GC) 卻認為該資料仍被引用而無法回收時,洩漏就發生了。
常見洩漏兇手:
- 意外的全域變數:不小心將資料掛載到
global物件上。 - 被遺忘的定時器:
setInterval啟動後從未被clearInterval。 - 閉包與大物件:閉包內引用了大型物件,且該閉包一直存在於記憶體中。
- 事件監聽器未移除:對同一個物件反覆
.on()卻從未.off()。
使用 Chrome DevTools 診斷
Node.js 內建了偵錯協議,讓你使用熟悉的 Chrome 工具進行效能剖析:
- 啟動偵錯模式:
node --inspect app.js - 開啟工具:在 Chrome 網址列輸入
chrome://inspect,點擊 "Open dedicated DevTools for Node"。
記憶體快照 (Heap Snapshot)
在 Memory 分頁,你可以點擊 Take Snapshot。
- 技巧:拍下一張快照,執行一些操作,再拍第二張。使用 "Comparison" 模式,找出那些「只增不減」的物件。
CPU 火燄圖 (Flame Graph)
在 Profiler 分頁,點擊 Start 並在你的 API 上進行壓力測試,完成後點擊 Stop。
- 尋找佔用比例最高的「寬長方形」,那通常就是消耗 CPU 最兇猛的程式碼熱點 (Hot Spot)。
程式碼級監控:process.memoryUsage()
你可以定期輸出記憶體指標來偵測趨勢。如果 rss 或 heapUsed 持續線性上升,就是洩漏的徵兆。
setInterval(() => {
const usage = process.memoryUsage();
console.log(
`[記憶體監控] RSS: ${Math.round(usage.rss / 1024 / 1024)}MB | HeapUsed: ${Math.round(usage.heapUsed / 1024 / 1024)}MB`
);
}, 10000);
指標說明:
- RSS (Resident Set Size):進程佔用的總實體記憶體(包含所有堆疊與 C++ 資源)。
- heapUsed:V8 引擎實際使用的記憶體空間。
- external:V8 管理的 C++ 物件佔用的記憶體(例如 Buffer)。
監控垃圾回收 (GC)
如果你懷疑 GC 頻率過高導致效能下降,可以使用以下指令啟動:
node --trace-gc app.js
這會在控制台即時輸出每次 GC 的耗時與空間回收情況。
總結
- 建立基準線 (Baseline):在部署前先了解正常的記憶體占用情況。
- 善用 Chrome DevTools 的「快照比對」來精確定位洩漏來源。
- 對於持續上升的
rss數值要保持高度警覺。