← 전체 글로 돌아가기

웹 개발

웹앱 메모리 누수를 찾는 순서

메모리 사용량이 점점 늘어나면 처음부터 뭔가 잘못됐을 거라고 가정하지 말고, 순서대로 확인해야 한다.

메모리 문제는 찾기가 까다롭다. 로컬에서는 잘되는데 운영 환경에서는 며칠 지나면서 서서히 늘어날 수 있기 때문이다. 이럴 땐 확인 순서가 중요하다.

먼저 사용자 영향을 파악하기

메모리 사용량이 높다고 해서 모두 긴급은 아니다. 현재 상황이 얼마나 심한지부터 파악해야 한다.

# 현재 메모리 사용량 확인
free -h

# 프로세스별 메모리 사용량
ps aux --sort=-%mem | head -20

# 시간대별 추이 보기
df -h

메모리가 80% 이상이면 빠르게 대응해야 하고, 50% 정도면 좀 더 여유 있게 원인을 찾을 수 있다.

원인 후보 좁혀가기

메모리 증가는 보통 세 가지 원인 중 하나다:

  1. 캐시가 무한정 쌓이는 경우
  2. 이벤트 리스너가 해제되지 않는 경우
  3. 데이터베이스 연결이 닫히지 않는 경우

Node.js라면 힙 스냅샷을 떠서 어느 객체가 많이 쌓여 있는지 본다.

# heap 사용량 실시간 모니터링
node --expose-gc app.js

# 힙 스냅샷 생성
kill -USR2 <pid>

빌드와 배포 환경 비교하기

Node.js 버전, 메모리 제한, 빌드 설정에 따라 동작이 달라질 수 있다. 로컬 개발 환경과 운영 환경의 차이를 확인한다.

# 패키지 버전 확인
npm ls | grep -E 'express|react|lodash'

# 현재 노드 버전
node -v

# 힙 크기 제한 확인
node -e "console.log(v8.getHeapStatistics())"

로컬에서는 32GB 램이 있지만, 운영 환경에선 1GB로 제한돼 있을 수 있다. 이런 차이가 메모리 문제를 키울 수 있다.

수정하기 전 작은 실험

한 번에 여러 개를 고치지 말고, 한 부분씩 수정한 후 다시 배포해서 메모리가 개선되는지 본다.

예를 들어 캐시 라이브러리의 TTL을 1시간에서 5분으로 줄였다면, 그것만 배포하고 24시간을 모니터링한다. 그 후 다음 수정으로 넘어간다.

변수 하나씩 바꿔야 어디가 영향을 미치는지 명확해진다.

문제 해결 후 남길 기록

메모리 문제를 해결했다면 뭐가 원인이었고 어떻게 고쳤는지 메모해두자. 몇 개월 뒤 같은 증상이 나타나면 이 기록이 큰 도움이 된다.

  • 원인: Redis 캐시가 2GB까지 쌓임
  • 해결: 캐시 expire 시간을 24시간에서 1시간으로 변경
  • 검증: 배포 후 72시간 모니터링하며 메모리가 안정적으로 유지됨