이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Memory Leak OOM 대응에서 붙잡아야 할 핵심 판단 기준은 무엇인가?
  • OOM은 메시지와 limit부터 분리한다라는 기준은 어떤 JVM/OS 신호로 확인되는가?
  • Java/Spring 코드에서 Memory Leak OOM 대응 판단 기준은 어떤 장애 신호로 드러나는가?

개요

이 문서의 주제는 Memory Leak OOM 대응이다. Memory leak, OOM, OOM kill, heap dump 수집과 임시 완화 기준을 정리한다.

먼저 붙잡을 기준은 다음 문장이다. OOM은 메시지와 limit부터 분리한다. OutOfMemoryError와 OS/cgroup OOM kill은 증거 위치와 조치가 다르므로, 재시작 전에 heap, RSS, container event, dump 가능성을 먼저 나눈다.

핵심 모델

  • 판단 기준: OOM은 메시지와 limit부터 분리한다.
  • Java heap OOM은 JVM 로그와 heap dump가 핵심이고, OS/cgroup kill은 kernel/container event가 핵심이다.
  • Heap used와 RSS가 다르게 움직이면 direct memory, metaspace, thread stack, native allocation을 의심한다.
  • Heap dump는 증거이면서 큰 disk write와 민감 정보 파일이므로 경로, 용량, 권한을 먼저 확인한다.
  • 재시작은 memory를 비우는 완화일 뿐 leak 원인 제거가 아니다.
  • 즉시 완화는 유입 제한, batch/export 중지, cache 축소, dump 판단, 안전한 재시작 순서로 진행한다.

문서별 핵심 구분

  • OOM 대응은 메시지 종류와 OS kill 여부 확인에서 시작한다.
  • heap dump 전 class histogram으로 의심 객체를 좁힌다.
  • 재시작은 완화일 뿐 leak 원인 제거가 아니다.

원리

Memory leak 대응은 “무엇이 계속 남는가”를 찾는 과정이다. Heap leak이면 GC 후에도 heap baseline이 내려오지 않고, native/direct leak이면 heap은 안정적인데 RSS가 오른다.

OOM 상황에서 가장 먼저 할 일은 프로세스가 어떤 방식으로 실패했는지 확인하는 것이다. Java exception이 남아 있으면 JVM 내부 한계일 가능성이 있고, 로그 없이 프로세스가 죽었다면 OS/cgroup kill을 먼저 본다.

Dump는 항상 정답이 아니다. 이미 disk가 부족하거나 개인정보가 들어 있는 heap을 안전하게 보관할 수 없다면 class histogram, GC log, NMT, /proc 정보부터 남기고 dump는 별도 판단한다.

Java/Spring 연결

  • Actuator heap/non-heap metric은 시작점이지만 RSS와 cgroup memory event를 대신하지 못한다.
  • Cache, session, batch list, 대량 export, file upload buffer, WebClient/Netty direct buffer는 memory 증가 후보가 된다.
  • HeapDumpOnOutOfMemoryError가 켜져 있어도 dump path 권한과 disk 용량이 없으면 증거가 남지 않는다.
  • Container OOM kill은 Java stack trace 없이 재시작으로만 보일 수 있어 orchestrator event와 dmesg를 확인한다.
  • Memory 완화는 traffic shed, cache clear, batch stop, instance recycle을 구분해 기록한다.

코드와 설정 예시

date -Is
jcmd <pid> GC.heap_info
jcmd <pid> GC.class_histogram | head -50
cat /proc/<pid>/status | grep -E 'VmRSS|VmSize|Threads'
dmesg | grep -i -E 'out of memory|killed process' | tail

예시는 heap 상태, 상위 객체 후보, process RSS, OS kill 흔적을 한 번에 맞추는 흐름이다. Heap dump는 이 정보로 필요성과 위험을 판단한 뒤 실행한다.

관찰 명령

jcmd <pid> GC.heap_info
jcmd <pid> GC.class_histogram | head
jcmd <pid> GC.heap_dump /tmp/heap.hprof
dmesg | grep -i 'killed process' | tail

Memory Leak OOM 대응 관찰 명령은 결론이 아니라 가설 확인 도구다. 운영 중에는 반복 간격, 대상 PID, 수집 시각을 함께 남기고 출력이 큰 명령은 범위를 제한한다.

지표 해석

신호먼저 의심할 것다음 확인
Java OutOfMemoryErrorheap/metaspace/direct 한계JVM log, heap info, dump option
로그 없이 process 재시작OS/cgroup OOM killdmesg, container event
Heap 안정, RSS 증가native/direct/thread stackNMT, /proc/<pid>/status
GC 후 baseline 상승heap leak, unbounded cachehistogram, heap dump

Memory 대응은 heap, RSS, GC after 사용량, swap, OOM event의 순서를 맞춰 본다. Heap OOM과 cgroup kill을 섞어 해석하면 dump와 limit 조정 판단이 틀어진다.

장애 상황에서 보는 순서

  1. 장애가 Java exception인지 OS/cgroup kill인지 로그로 구분한다.
  2. heap, non-heap, RSS, container limit, swap 활동을 같은 시각에 남긴다.
  3. GC.class_histogram으로 큰 객체 후보를 빠르게 본다.
  4. Heap dump를 뜰지 disk, 개인정보, 장애 부하를 기준으로 결정한다.
  5. 즉시 완화는 cache 축소, batch/export 중지, 유입 제한, 안전한 재시작 순서로 적용한다.
  6. 근본 수정은 leak 제거, cache 상한, batch streaming, memory limit/option 조정으로 분리한다.

재시작 후 memory가 내려가도 leak이 사라졌다고 보지 않는다. 증가 기울기와 어떤 완화가 효과를 냈는지 기록해야 재발 시 판단 시간이 줄어든다.

실전 팁

  • Heap dump를 떠야 한다면 파일 경로가 서비스 disk를 압박하지 않는지 먼저 본다.
  • Class histogram은 dump보다 가볍지만 stop-the-world 영향을 줄 수 있으므로 장애 중 반복 실행을 제한한다.
  • Cache clear는 완화일 뿐이다. cache key 수, TTL, max size, eviction 정책을 따로 고쳐야 한다.
  • OS kill이면 Java 로그만 뒤지지 말고 orchestrator event, kernel log, cgroup memory를 먼저 본다.
  • Memory 증설은 재발 시간을 늦출 수 있지만 leak 속도가 그대로면 다시 장애가 난다.

주니어 팁

  • Java OOM과 OS OOM kill은 다르다. 하나는 JVM이 예외를 남기고, 다른 하나는 OS가 프로세스를 죽일 수 있다.
  • Heap이 낮아도 RSS가 높으면 heap 밖 memory를 의심한다.
  • Dump를 뜨기 전에는 “어디에 저장되고 누가 볼 수 있는가”를 확인한다.

시니어 팁

  • Memory budget은 heap, direct, metaspace, stack, page cache로 나눠 capacity plan에 넣는다.
  • Batch/export/upload 기능에는 streaming, chunk size, backpressure, max file size를 설계 기준으로 둔다.
  • Dump 보관 정책에는 암호화, 보존 기간, 접근 권한, 삭제 절차를 포함한다.

Guru급 팁

  • Leak 분석의 핵심은 절대량보다 증가 기울기다. 같은 부하에서 after-GC baseline이 계속 오르는지 본다.
  • Heap dump 분석 결과는 객체 타입만이 아니라 retention path와 소유자 코드까지 연결해야 수정 가능하다.
  • Memory 완화 후에는 GC pause, cache hit ratio, latency가 어떻게 바뀌었는지 함께 봐야 한다.

위험 신호!

  • OOM 종류를 구분하지 않고 heap만 키운다.
  • Heap dump 경로와 disk 여유를 확인하지 않는다.
  • OS/cgroup kill을 Java exception이 없다는 이유로 놓친다.
  • Heap 안정, RSS 증가 상황에서 native/direct memory를 보지 않는다.
  • 재시작으로 회복됐다는 이유로 증가 기울기와 큰 객체 후보를 남기지 않는다.

확인 질문

확인 질문

  • Java OOM과 OS/cgroup OOM kill을 구분해야 하는 이유는 무엇인가?
    • 증거 위치와 조치가 다르기 때문이다. Java OOM은 JVM 로그와 dump가 핵심이고, OS/cgroup kill은 kernel/container event와 limit이 핵심이다.
  • Heap dump를 뜨기 전에 확인해야 할 것은 무엇인가?
    • Dump 필요성, 저장 경로, disk 여유, 권한, 민감 정보 보관 정책, 추가 부하를 확인해야 한다.
  • Memory leak 보고서에 반드시 남길 것은 무엇인가?
    • Heap/RSS/cgroup 추세, after-GC baseline, 큰 객체 후보, dump 여부, 완화 조치, 재발 방지 수정을 남겨야 한다.

참고 문서