Files
2nd/01_Archive/2026-04-20/Node.js 성능 디버깅.md
T

5.0 KiB

Node.js 성능 디버깅

📌 Brief Summary

Node.js 성능 디버깅은 주로 V8 엔진의 힙(Heap) 메모리 사용량을 추적하고 가비지 컬렉션(GC) 동작을 분석하여 애플리케이션의 성능 저하 및 메모리 누수(Memory Leak)를 해결하는 과정이다 [1, 2]. 힙 스냅샷(Heap Snapshot), 할당 타임라인, GC 트레이싱 등의 진단 도구를 활용하여 메모리 내에서 불필요하게 유지되는 참조 객체를 식별한다 [3-5]. 이와 더불어, 실시간 모니터링 API 및 V8 명령줄 플래그 튜닝을 통해 메모리 한계를 조정하여 서버 안정성과 처리량을 최적화할 수 있다 [6-8].

📖 Core Content

  • 메모리 누수의 정의와 주요 패턴 Node.js에서 메모리 누수는 가비지 컬렉터(GC)에 의해 수거되어야 할 객체가 클로저(Closure), 전역 변수 등에 의해 여전히 참조를 유지하고 있을 때 발생한다 [3, 9]. 이로 인해 시간이 지남에 따라 메모리가 지속적으로 증가하며, 결과적으로 프로세스가 Out-Of-Memory(OOM) 오류로 인해 중단될 수 있다 [10, 11]. Node.js 환경에서 가장 흔하게 발생하는 누수 패턴은 다음과 같다:

    • 이벤트 리스너 누적: on('event', fn)을 지속적으로 추가하고 제거하지 않으면 해당 콜백 함수와 관련된 메모리가 누수된다 [12].
    • 클로저(Closure) 변수 보존: 비동기 체인이나 스코프를 공유하는 클로저 내부에 큰 객체를 캡처해 두면 해당 클로저의 수명 주기 동안 메모리가 유지된다 [13, 14].
    • 무제한 캐시(Unbounded Cache): 인메모리 캐시의 크기나 만료를 제한하지 않으면 데이터가 끝없이 축적된다 [14].
    • 정리되지 않은 타이머: clearInterval이 호출되지 않은 setInterval은 콜백 클로저에 있는 모든 항목의 GC를 방지한다 [15, 16].
    • 닫히지 않은 스트림 및 소켓: 올바르게 종료되지 않은 스트림은 내부 버퍼와 네트워크 핸들을 점유한다 [16].
  • 메모리 디버깅 및 프로파일링 도구

    • 힙 스냅샷(Heap Snapshots): 특정 시점의 전체 메모리 상태를 캡처하는 기능으로, Chrome DevTools에서 스냅샷들을 비교('Comparison' 뷰)하여 메모리 누수를 검사할 수 있다 [4, 17-19]. --inspect 플래그로 연결하거나 heapdump 패키지를 사용해 캡처한 뒤 '할당된 후 해제되지 않은 객체(Objects allocated between snapshots)'를 찾아낸다 [4, 5, 18].
    • 할당 타임라인(Allocation Timeline): 특정 시간 동안의 메모리 할당을 시각적으로 추적한다 [17, 20]. 가비지 컬렉션 후에도 살아있는 객체는 파란색 막대로 표시되며, 이를 통해 메모리 누수 후보를 특정할 수 있다 [5, 17, 20].
    • GC 트레이싱(--trace-gc): --trace-gc 플래그를 사용해 실행하면 가비지 컬렉션의 세부 발생 시간, 소요 시간, GC 전후의 힙 용량 변화를 콘솔에서 확인할 수 있다 [5, 21, 22]. 만약 Mark-sweep(오래된 세대 GC) 작업이 지나치게 빈번하거나 GC 이후에도 힙이 원래 수준으로 줄어들지 않으면 메모리 누수의 강력한 신호이다 [23].
    • 메모리 모니터링 API: 코드 내에서 process.memoryUsage()를 호출하여 프로세스에 할당된 전체 메모리(rss)와 힙의 총량(heapTotal), 현재 사용 중인 힙(heapUsed) 등을 실시간으로 파악할 수 있다 [6, 7].
  • 메모리 튜닝 및 최적화 Node.js는 V8 엔진의 메모리 제한 및 GC 빈도를 직접 제어할 수 있는 명령줄 플래그를 제공한다 [7].

    • --max-old-space-size: 수명이 긴 객체들이 저장되는 Old Space의 크기 한도를 설정하여, 지속적인 데이터를 다룰 때 OOM을 지연시키거나 예방할 수 있다 [8, 24].
    • --max-semi-space-size: 빈번하게 생성 및 소멸되는 객체가 저장되는 New Space의 크기를 조절한다. 처리량이 많은 상황에서 이 크기를 늘리면 잦은 Scavenge(마이너 GC) 사이클을 줄여 성능을 향상할 수 있다 [24, 25].
    • --expose-gc: 이를 설정하면 애플리케이션 코드 내에서 global.gc()를 수동으로 호출하여 대량의 데이터 처리 후 명시적으로 메모리를 회수할 수 있다 [26, 27].

🔗 Knowledge Connections


Last updated: 2026-04-19