SHIN STORYSHIN STORY
홈포스트C#TypeScriptNext.jsNode.js시리즈
</>SHIN STORY

sdf

탐색

  • 홈
  • 모든 포스트
  • 시리즈
  • 검색

카테고리

  • C#
  • TypeScript
  • Next.js
  • Node.js
  • 알고리즘
  • 개발 도구

© 2025 Shin Blog. All rights reserved.

GitHubRSS
목록으로
Node.js#Node.js#Performance

Node.js 메모리 누수 찾고 수정하기

SHIN

2026년 4월 27일2분 읽기0
📚

Node.js 실전 팁 20선

20편
  1. 3Node.js Stream으로 대용량 파일 처리하기
  2. 4Worker Threads로 CPU 집약 작업 처리하기
  3. 5cluster 모듈로 멀티코어 CPU 100% 활용하기
  4. 6child_process로 외부 명령 실행하기
  5. 7fs/promises로 파일 시스템 다루기
  6. 20Node.js Event Loop 완전 정복
  7. 20Node.js path 모듈 완전 정복
  8. 20환경 변수 관리 — .env, dotenv, 그리고 검증
  9. 20EventEmitter 패턴으로 느슨한 결합 구현하기
  10. 20Node.js crypto 모듈로 해싱과 암호화 구현하기
  11. Node.js 메모리 누수 찾고 수정하기현재
  12. 20Express 미들웨어 패턴과 에러 처리
  13. 20Node.js CJS vs ESM 모듈 시스템 완전 정리
  14. 20Node.js Buffer와 인코딩 완전 가이드
  15. 20PM2로 Node.js 프로세스 관리하기
  16. 20Node.js HTTP 서버 직접 구현하기
  17. 20Node.js 성능 프로파일링 실전 가이드
  18. 20Node.js npm 스크립트 완전 활용하기
  19. 20Node.js 보안 체크리스트 10가지
  20. 20Node.js 테스팅 전략 — 단위, 통합, E2E 테스트

Node.js 메모리 누수 찾고 수정하기

Node.js 서버가 시간이 지남에 따라 메모리를 계속 먹으면 메모리 누수를 의심해야 합니다.

누수의 주요 원인

원인설명
전역 변수 축적배열/맵에 계속 추가, 정리 안 함
이벤트 리스너 미제거컴포넌트 해제 시 off() 미호출
클로저 참조오래된 대형 객체를 클로저가 붙잡음
캐시 무한 성장Map/Object에 TTL 없이 계속 저장
Timer 미정리setInterval clearInterval 미호출

1) 전역 캐시 누수

CODE
// ❌ 누수 - 캐시 크기 무제한
const cache = new Map();
app.get('/user/:id', async (req, res) => {
  if (!cache.has(req.params.id)) {
    cache.set(req.params.id, await db.user.findById(req.params.id));
  }
  res.json(cache.get(req.params.id));
});

// ✅ LRU 캐시로 크기 제한
import LRU from 'lru-cache';
const cache = new LRU({ max: 500, ttl: 1000 * 60 * 5 }); // 최대 500개, 5분 TTL

2) 이벤트 리스너 누수

CODE
// ❌ 누수 - 요청마다 리스너 추가, 제거 안 함
server.on('connection', (socket) => {
  process.on('exit', () => socket.destroy()); // 요청마다 추가됨!
});

// ✅ WeakRef + 명시적 제거
server.on('connection', (socket) => {
  const onExit = () => socket.destroy();
  process.once('exit', onExit); // once 사용
  socket.on('close', () => process.off('exit', onExit)); // 소켓 닫힐 때 제거
});

3) 메모리 사용량 모니터링

CODE
function logMemory(label = '') {
  const m = process.memoryUsage();
  const fmt = (b) => (b / 1024 / 1024).toFixed(2) + ' MB';
  console.log(`[Memory ${label}] heap: ${fmt(m.heapUsed)}/${fmt(m.heapTotal)}, RSS: ${fmt(m.rss)}`);
}

// 주기적 모니터링
setInterval(() => logMemory('periodic'), 30_000);

4) --inspect로 Chrome DevTools 프로파일링

CODE
node --inspect app.js
# Chrome에서 chrome://inspect 접속
# Memory 탭 → Take heap snapshot
# 스냅샷 비교로 누수 객체 식별

5) WeakMap/WeakSet으로 안전한 참조

CODE
// ❌ Map은 강한 참조 — GC 방해
const metadata = new Map();
function attach(obj) { metadata.set(obj, { ts: Date.now() }); }

// ✅ WeakMap — 객체가 GC되면 자동 정리
const metadata = new WeakMap();
function attach(obj) { metadata.set(obj, { ts: Date.now() }); }

6) 누수 감지 자동화

CODE
// 힙 임계값 초과 시 경고
const HEAP_LIMIT = 512 * 1024 * 1024; // 512 MB

setInterval(() => {
  const { heapUsed } = process.memoryUsage();
  if (heapUsed > HEAP_LIMIT) {
    console.error(`힙 임계값 초과: ${(heapUsed / 1024 / 1024).toFixed(0)} MB`);
    // 알림 발송, 재시작 트리거 등
  }
}, 10_000);
공유
S

SHIN

.NET 개발자입니다

GitHub
Node.js crypto 모듈로 해싱과 암호화 구현하기

이전 포스트

Node.js crypto 모듈로 해싱과 암호화 구현하기

다음 포스트

Express 미들웨어 패턴과 에러 처리

Express 미들웨어 패턴과 에러 처리

같은 카테고리 포스트

Node.js 테스팅 전략 — 단위, 통합, E2E 테스트

Node.js 테스팅 전략 — 단위, 통합, E2E 테스트

2026년 5월 6일· 2분
Node.js 보안 체크리스트 10가지

Node.js 보안 체크리스트 10가지

2026년 5월 5일· 2분
Node.js npm 스크립트 완전 활용하기

Node.js npm 스크립트 완전 활용하기

2026년 5월 4일· 1분

댓글