Java Heap Dump에서 먼저 볼 것들
마지막 업데이트

Java Heap Dump에서 먼저 볼 것들


Java heap dump 를 떴을 때 가장 어려운 부분은, 지금 보고 있는 것이 진짜 leak 인지, 일시적인 workload burst 인지, 아니면 backlog 때문에 객체가 예상보다 오래 살아남은 상황인지를 구분하는 것입니다. heap dump 는 실제 object graph 를 보여 주지만, 해석은 여전히 필요합니다.

짧게 말하면 핵심은 이것입니다. raw object count 보다 retained memory 부터 봐야 합니다. instance 수가 가장 많은 class 가 항상 진짜 culprit 는 아닙니다. 어떤 object graph 가 retained heap 을 지배하는지, 그리고 왜 아직 reachable 한지가 더 중요합니다.

Java 전체 증상 분기부터 다시 보고 싶다면 Java Troubleshooting Guide 로 먼저 돌아가도 좋습니다.


object count 보다 retained memory 부터 본다

instance 가 많다고 자동으로 문제가 되는 것은 아닙니다.

더 중요한 것은 아래입니다.

  • retained size
  • dominator 관계
  • reference chain
  • 그 객체가 아직 살아 있어야 하는지 여부

그래서 단순 histogram 보다 dominator 와 GC root 까지의 경로가 훨씬 유용한 경우가 많습니다.


heap dump 는 어떤 질문에 가장 유용한가

heap dump 는 보통 이런 질문에 답할 때 가장 가치가 큽니다.

  • 지금 가장 많은 메모리를 붙잡고 있는 것은 무엇인가
  • 이 성장이 cache, backlog, leaked reference 중 어디에서 오는가
  • 객체가 예상보다 오래 살아남고 있는가
  • 이 현상이 OOM 이나 긴 GC pause 와 이어지는가

적절한 시점에 뜬 dump 하나가 추측을 concrete retention path 로 바꿔 주기도 합니다.


흔한 원인

1. 큰 collection 이 계속 커진다

가장 자주 보이는 패턴 중 하나입니다.

map, list, queue, cache 는 아래 상황에서 heap 을 지배하기 쉽습니다.

  • eviction 이 없다
  • 소비 속도가 느리다
  • 요청별 데이터가 중복 저장된다
  • 각 entry 가 생각보다 크다

이건 고전적인 leak 이라기보다 unbounded retention 인 경우도 많습니다.

2. backlog 가 request data 를 붙잡고 있다

queued work 가 payload, context, response, closure 를 예상보다 오래 살아 있게 만들 수 있습니다.

시스템이 뒤처지는 중이라면, heap dump 는 원래 성능 병목보다 queue 증상을 더 또렷하게 보여 줄 수도 있습니다.

3. reference chain 이 cleanup 을 막는다

수거되어야 할 객체가 아래를 통해 계속 reachable 할 수 있습니다.

  • singleton
  • static holder
  • thread local
  • listener registry
  • 실질적 만료가 없는 cache

이럴 때 GC root 까지의 path 가 특히 중요해집니다.

4. snapshot 을 뜬 시점이 적절하지 않다

짧은 burst 중에 잡은 dump 는 장기 leak 이 아니라 일시 압력을 보여 줄 수 있습니다.

그래서 dump 하나도 유용하지만, traffic 타이밍과 여러 dump 비교가 더 좋은 경우가 많습니다.

5. 큰 retained graph 는 이야기의 일부일 뿐이다

dump 에서 큰 retained structure 가 보여도, incident 의 출발점은 다른 곳일 수 있습니다.

  • queue buildup
  • 느린 downstream dependency
  • traffic spike
  • retry storm

즉 dump 는 도움이 되지만, 운영 맥락 속에서 읽어야 더 정확합니다.


실전 점검 순서

1. 가장 큰 retained object 와 dominator 를 찾는다

instance 수가 많은 것보다 retained heap 을 지배하는 것을 먼저 보세요.

이 단계가 attention 을 어디에 써야 할지 정해 줍니다.

2. 그 객체를 살려 두는 reference path 를 본다

질문은 이렇습니다.

  • 어떤 object 가 이 graph 를 소유하고 있는가
  • 그 owner 는 지금도 살아 있어야 하는가
  • 의도된 reference 인가, accidental reference 인가

이 단계에서 “메모리가 높다” 가 실제 코드 경로 문제로 바뀌는 경우가 많습니다.

3. cache, queue, large collection 이 기대 범위를 벗어났는지 비교한다

크다는 사실만 보면 안 되고, 설계 기대치 대비 큰지를 물어야 합니다.

예를 들면:

  • 현재 load 에서 queue size 가 정상인가
  • cache 에 bound 가 있는가
  • 배포 이후 collection 이 갑자기 커졌는가

4. heap dump 시점과 traffic 또는 deployment 변화를 비교한다

같은 retained graph 도 언제 dump 를 떴는지에 따라 의미가 달라집니다.

짧은 burst 중의 snapshot 과, 몇 시간에 걸친 steady growth 뒤 snapshot 은 같은 식으로 읽으면 안 됩니다.

5. dump 가 retention 을 확인해 주면 pause 또는 OOM 증상과 다시 연결한다

같은 retained graph 가 GC pause 를 늘리거나 서비스를 failure 로 밀고 있다면, 그 증상과 heap evidence 를 연결해서 봐야 합니다.


예시: leak 처럼 보이는 queue retention

jcmd <pid> GC.heap_dump heap.hprof

예를 들어 dump 에서 thread pool queue 안의 task 들이 많은 request payload object 를 붙잡고 있다면, 처음엔 고전적인 memory leak 처럼 보일 수 있습니다. 하지만 실제 문제는 worker 가 느려져 backlog 가 생겼고, 그 때문에 객체가 오래 살아남은 것일 수 있습니다.

그래서 heap dump 는 queue 와 throughput 신호와 함께 읽는 편이 좋습니다.


retained graph 를 찾은 뒤 무엇을 바꾸면 좋나

cache 나 collection 이 unbounded 라면

real limit, eviction, lifecycle control 이 필요합니다.

backlog 가 데이터를 너무 많이 붙잡는다면

queue buildup 을 줄이고, task 가 오래 기다리게 만드는 throughput bottleneck 을 먼저 고쳐야 합니다.

thread local 이나 static reference 가 데이터를 잡고 있다면

cleanup 과 ownership 경계를 더 명확하게 해야 합니다.

dump 가 짧은 burst 를 반영한 것이라면

바로 leak 으로 단정하지 말고 이후 snapshot 과 비교해야 합니다.

같은 graph 가 dump 마다 계속 커진다면

강한 leak 또는 retention 신호로 보고 owner path 를 직접 추적해야 합니다.


장애 중에 던져볼 질문

이 질문이 꽤 유용합니다.

가장 많은 retained memory 를 가진 object graph 는 무엇이고, 그 ownership 이 지금 request 또는 task lifecycle 상 여전히 존재해야 맞는가?

이 질문이 class count 만 보는 것보다 훨씬 빨리 fix 로 이어집니다.


FAQ

Q. object count 가 크면 leak 인가

항상은 아닙니다. retained size 와 reachability 가 count 보다 더 중요합니다.

Q. dump 를 여러 번 떠야 하나

같은 retained graph 가 시간에 따라 계속 커지는지 비교하려면 그렇습니다.

Q. 가장 빠른 첫 단계는 무엇인가

가장 큰 dominator 와 그 reference path 를 찾는 것입니다.

Q. heap dump 가 true leak 이 아니라 backlog 를 보여 줄 수도 있나

그렇습니다. queued work 는 classic forever leak 이 아니어도 실제 memory pressure 를 크게 만들 수 있습니다.


Sources:

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.