Senior #memory-leak#debugging#heap#v8
Memory leak trong Node.js: nguyên nhân phổ biến và cách debug?
⚡ Trả lời nhanh
Leak xảy ra khi object còn được tham chiếu nên GC không thu hồi: cache/Map không giới hạn, listener không gỡ, timer, closure giữ biến lớn, biến global. Debug bằng heap snapshot (--inspect + Chrome DevTools), so sánh nhiều snapshot và theo dõi process.memoryUsage().
Nguyên nhân thường gặp:
- Cache dạng
Map/object không có giới hạn hoặc TTL (dùng LRU, hoặcWeakMapkhi key là object). emitter.ontrong mỗi request mà khôngoff: cảnh báoMaxListenersExceededWarninglà dấu hiệu.setIntervalkhôngclearInterval; closure giữ tham chiếu tới object lớn.- Mảng/biến global tích lũy (log, metric, session trong RAM).
Quy trình điều tra:
- Quan sát
heapUsedtăng đều sau mỗi lần GC (đường răng cưa đi lên),process.memoryUsage(). - Chạy
node --inspect app.js, mởchrome://inspect, tab Memory. - Chụp snapshot, tạo tải, chụp lại; dùng “Comparison” để tìm object có số lượng tăng, xem Retainers để biết ai đang giữ.
- Có thể tạo snapshot từ xa bằng
v8.writeHeapSnapshot().
const cache = new Map();
app.get("/user/:id", async (req, res) => {
if (!cache.has(req.params.id)) cache.set(req.params.id, await load(req.params.id));
res.json(cache.get(req.params.id)); // leak: Map phình vô hạn
});