이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
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' | tailMemory Leak OOM 대응 관찰 명령은 결론이 아니라 가설 확인 도구다. 운영 중에는 반복 간격, 대상 PID, 수집 시각을 함께 남기고 출력이 큰 명령은 범위를 제한한다.
지표 해석
| 신호 | 먼저 의심할 것 | 다음 확인 |
|---|---|---|
Java OutOfMemoryError | heap/metaspace/direct 한계 | JVM log, heap info, dump option |
| 로그 없이 process 재시작 | OS/cgroup OOM kill | dmesg, container event |
| Heap 안정, RSS 증가 | native/direct/thread stack | NMT, /proc/<pid>/status |
| GC 후 baseline 상승 | heap leak, unbounded cache | histogram, heap dump |
Memory 대응은 heap, RSS, GC after 사용량, swap, OOM event의 순서를 맞춰 본다. Heap OOM과 cgroup kill을 섞어 해석하면 dump와 limit 조정 판단이 틀어진다.
장애 상황에서 보는 순서
- 장애가 Java exception인지 OS/cgroup kill인지 로그로 구분한다.
- heap, non-heap, RSS, container limit, swap 활동을 같은 시각에 남긴다.
GC.class_histogram으로 큰 객체 후보를 빠르게 본다.- Heap dump를 뜰지 disk, 개인정보, 장애 부하를 기준으로 결정한다.
- 즉시 완화는 cache 축소, batch/export 중지, 유입 제한, 안전한 재시작 순서로 적용한다.
- 근본 수정은 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 여부, 완화 조치, 재발 방지 수정을 남겨야 한다.