TestForge | Aidevops | 📊 Plogger ✍️ Blog 📚 Docs
plogger

AI DevOps Korea

AI 서비스 개발, 운영, 성능개선을 하나의 루프로 연결합니다

aidevops.kr에서 LLMOps, RAG, AI Agent, 관측성, 평가, 비용-성능 최적화를 실전 운영 관점으로 정리합니다.

Java 메모리 누수 추적 플레이북

· 수정 4월 28일

대부분의 Java 메모리 문제는 갑작스러운 크래시로 시작되지 않습니다. 릴리스가 반복될수록 재시작이 잦아지고, pause가 길어지고, 여유 메모리가 서서히 사라지는 형태로 시작됩니다.

먼저 증가 패턴을 분류해야 한다

누수라고 단정하기 전에 먼저 봐야 할 질문이 있습니다.

  • GC 이후에도 heap 사용량이 돌아오지 않는가
  • 메모리 증가는 트래픽 패턴 때문인가, 배포 이후 누적되는가
  • off-heap buffer나 thread stack이 원인일 가능성은 없는가

첫 단계는 추측이 아니라 분류입니다.

흔한 누수 원인

  • eviction 없는 in-memory cache
  • 해제되지 않는 listener와 callback
  • static 참조에 저장된 request context
  • 오래 사는 singleton 객체에 붙은 대형 collection

대개 언어의 결함이라기보다 생명주기 설계 문제입니다.

dump에서는 retention 소유자를 찾아야 한다

Heap dump가 중요한 이유는 어떤 객체가 아직도 강한 참조로 살아 있는지 보여주기 때문입니다. 볼 포인트는 다음과 같습니다.

  • dominator tree 크기
  • 비정상적으로 큰 collection
  • 재배포 후에도 남아 있는 classloader
  • 큰 string, byte array, serialization buffer

중요한 질문은 “무슨 객체가 큰가”가 아니라 “왜 아직도 이 객체를 붙잡고 있는가”입니다.

런타임 메트릭과 코드 경계를 같이 봐야 한다

메모리 디버깅은 그래프와 릴리스를 연결할 때 빨라집니다. 예를 들면:

  • old gen 점유율
  • allocation rate 급증 구간
  • full GC 빈도
  • 증가와 상관관계가 있는 endpoint나 background job

이렇게 해야 dump를 열기 전에 후보군을 좁힐 수 있습니다.

예방 규칙이 더 중요하다

좋은 팀은 다음 같은 가드레일을 둡니다.

  • eviction 있는 bounded cache
  • 명시적인 lifecycle cleanup
  • 지연시간뿐 아니라 메모리 추세를 보는 부하 테스트
  • 릴리스별 heap 추세 비교 대시보드

최고의 누수 분석은 한 번의 영웅적 디버깅으로 끝나지 않고, 같은 실패가 다시 오지 않게 만드는 설계 규칙으로 이어집니다.

Continue Reading

다음으로 읽기 좋은 글

다음 탐색

이 주제를 시스템 관점으로 더 이어서 보기