Node.js --expose-gc로 메모리 누수 디버깅하기
문제
장시간 실행되는 Node.js 앱(MQTT 클라이언트, 배치 프로세서 등)에서 메모리가 계속 올라간다. GC가 제대로 돌고 있는 건지, 진짜 누수인 건지 구분이 안 된다.
해결
# --expose-gc로 실행하면 global.gc()를 호출할 수 있다
node --expose-gc app.js
# Docker에서
CMD ["node", "--expose-gc", "--max-old-space-size=512", "dist/index.js"]
// 메모리 상태 확인 함수
function logMemory(label) {
if (global.gc) global.gc(); // 수동 GC 실행
const usage = process.memoryUsage();
console.log(`[${label}] Heap: ${Math.round(usage.heapUsed / 1024 / 1024)}MB / ${Math.round(usage.heapTotal / 1024 / 1024)}MB`);
}
// 사용 예시
logMemory('시작');
await processLargeData();
logMemory('처리 후'); // GC 후에도 메모리가 안 줄면 → 누수
핵심 포인트
global.gc()를 호출한 후에도heapUsed가 계속 증가하면 진짜 메모리 누수다. GC가 회수할 수 없는 객체가 어딘가에 참조되고 있는 거다.--max-old-space-size=512로 힙 크기를 제한하면, 누수가 있을 때 빨리 OOM으로 터져서 문제를 빨리 발견할 수 있다.- 프로덕션에서는
--expose-gc를 쓰지 않는 게 좋다. 수동 GC는 성능에 영향을 준다. 디버깅할 때만 쓰자.