Node.js 메모리 누수 탐지와 힙 스냅샷 분석
Node.js 환경에서 메모리 누수 발생 원인과 힙 스냅샷을 활용한 분석 흐름, 실무에서 적용 가능한 진단과 해석 방법론
목차
서론: 왜 메모리 누수를 찾아야 하는가
Node.js 서비스는 장시간 실행되는 프로세스 특성상 메모리 누수에 취약하다. 작은 누수도 누적되면 점진적으로 메모리 사용량이 증가하고, 결국 OOM(Out Of Memory)이나 성능 저하로 이어진다. 본문에서는 초보자도 따라할 수 있도록 Node 메모리 누수 디버깅 관점에서 힙 스냅샷 분석 Node 환경에서의 실제 흐름을 차근히 설명한다.
메모리 누수의 전형적 원인
생성되고 해제되지 않는 참조
가장 흔한 원인은 불필요한 참조가 남아 GC(가비지 컬렉터)에 의해 회수되지 않는 경우다. 콜백, 클로저, 전역 캐시, 이벤트 리스너 등이 대표적이다.
메모리 풀의 오용
버퍼나 캐시를 제한 없이 증가시키면 누수처럼 보이는 현상이 발생한다. 의도된 캐시라도 성장 한계를 설계해야 한다.
준비: 도구와 환경
필수 도구
- Node.js(최신 LTS 권장)
- Chrome DevTools(원격 디버깅 포함)
- heapdump 또는 v8-profiler 같은 모듈
- pm2 같은 프로세스 매니저(장시간 서비스 테스트 시 유용)
실행 옵션 예시
프로세스를 --inspect 또는 --inspect-brk 옵션으로 실행하면 Chrome DevTools에서 힙 스냅샷을 직접 수집할 수 있다. 장비에서 직접 스냅샷을 찍기 어려운 경우 heapdump 모듈로 파일을 생성해 로컬에서 열어 분석한다.
실전 흐름: 메모리 누수 진단 과정
1. 이상 징후 관찰
- 메모리 사용량의 점진적 상승 모니터링
- GC 빈도 증가 또는 응답 지연
- 프로세스 재시작 시 메모리 사용량 리셋
2. 재현 가능한 시나리오 구성
부하 테스트나 장시간 실행 테스트로 누수가 재현되는지를 확인한다. 재현이 가능해야 힙 스냅샷 비교가 의미 있다.
3. 힙 스냅샷 수집과 비교
다음 절차로 스냅샷을 수집한다.
- 초기 상태 스냅샷(서비스 시작 직후)
- 부하 후 스냅샷(문제가 발생한 시점)
- 추가 작업 후 스냅샷(변화 추적용)
힙 스냅샷 분석(Node.js 메모리 프로파일링)
Chrome DevTools에서의 기본 해석
DevTools에서 객체 타입별 인스턴스 수와 retained size를 확인한다. retained size가 큰 객체 계층은 누수의 후보다. 특히 Closure나 ArrayBuffer 같은 타입을 주의 깊게 본다.
주요 지표와 의미
- Shallow Size: 객체 자체가 차지하는 메모리
- Retained Size: 해당 객체를 제거하면 함께 사라지는 메모리 양
- Dominators: 메모리를 점유하는 주요 노드(누수 원인 추적에 유용)
예제: 단순 메모리 누수 코드
아래 코드는 전형적인 누수 패턴을 보여준다. 루프에서 배열에 항목을 계속 추가하지만 제거하지 않는다.
const leaky = [];
setInterval(() => {
leaky.push(new Array(1000).fill('leak'));
}, 1000);
heapdump 모듈을 이용한 스냅샷 생성
const heapdump = require('heapdump');
// 원하는 시점에 힙 덤프 생성
heapdump.writeSnapshot('/tmp/' + Date.now() + '.heapsnapshot');
생성된 .heapsnapshot 파일을 Chrome에서 열어 분석한다. 파일은 DevTools의 Memory 탭에서 드래그 앤 드롭으로 로드할 수 있다.
분석 팁: 무엇을 비교할 것인가
- 스냅샷 간 특정 타입의 인스턴스 수 변화
- Retained Size가 큰 도미네이터의 변화
- 불필요한 전역 참조나 이벤트 리스너 누적 여부
레퍼런스 체인 추적
문제가 되는 객체를 선택하고 "Retainers" 패널로 올라가면 어떤 경로로 참조가 유지되는지 확인 가능하다. 이 체인을 따라가며 코드의 어느 부분에서 참조를 유지하는지 찾아낸다.
완화와 해결 전략
코드 차원의 조치
- 불필요한 전역 변수 제거
- 이벤트 리스너를 반드시 제거
- 캐시에 최대 크기 설정 및 만료 정책 적용
운영 관점 조치
- 메모리 모니터링과 경보 정책 설정
- 롤링 재시작이나 메모리 한계치 기반 자동 복구
- 서비스 분리로 메모리 부담 분산
마무리: 분석의 반복과 검증
힙 스냅샷 분석은 한 번으로 끝나지 않는다. 변경 후에도 동일한 시나리오로 검증해 누수가 해결됐는지 확인해야 한다. Node 메모리 누수 디버깅은 모니터링, 재현, 스냅샷 수집, 분석, 수정을 반복하는 과정이다. heap snapshot 분석 Node 관점의 절차를 숙지하면 문제 파악 속도가 크게 빨라진다.
참고 사항
- 프로덕션에서 직접 디버깅 시 성능 영향 고려
- 스냅샷 파일은 크기가 클 수 있어 저장소 관리 필요