heap OOM(OutOfMemoryError)을 분석하려면 문제가 발생한 순간의 heap dump가 필요합니다. 그런데 OOM이 발생하면 JVM 프로세스는 이미 종료된 뒤입니다. 프로세스가 죽는 순간에 어떻게 dump를 뜰 수 있을까요?
JVM은 heap OOM발생시 dump를 하는 옵션이 있습니다. 이 글에서는 JVM의 heap dump 옵션과 관련 배경에 대해 정리했습니다.
java -Xmx2g \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/dumps/heap.hprof \
-jar app.jar
heap OOM은 왜 분석하기 어려운가
JVM에서 실행되는 애플리케이션은 객체를 생성할 때 heap이라는 메모리를 사용합니다. heap은 유한한 자원이어서, heap보다 더 큰 메모리를 요구하는 객체를 생성하거나 GC로도 더 이상 heap을 정리하지 못하면 OOM이 발생하고 해당 프로세스는 종료됩니다.
- 객체 생성 흐름
→ 자리 없으면 young generation만 정리 (minor GC)
→ 그래도 자리 없으면 heap 전체 정리 (full GC)
→ 그래도 자리 없으면 OOM (java.lang.OutOfMemoryError: Java heap space)
OOM을 분석하려면 애플리케이션 로그로 어림짐작하거나 heap dump 파일이 필요합니다. 문제는 heap dump가 문제가 발생한 시점에 떠야 의미가 있다는 점입니다. OOM이 발생하면 프로세스가 이미 종료되어, 정작 필요한 그 시점에는 dump를 뜰 수 없습니다.
OOM 순간에 heap dump하는 방법: JVM 옵션
JVM은 이 상황을 위한 옵션을 제공합니다. HeapDumpOnOutOfMemoryError 옵션을 지정하면, heap OOM이 발생하는 순간 프로세스가 종료되기 전에 JVM이 heap dump를 생성합니다. HeapDumpPath 옵션으로 dump 파일 위치를 지정합니다.
java -Xmx2g \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/dumps/heap.hprof \
-jar app.jar
heap OOM과 관련된 JVM 옵션은 아래와 같습니다.
- -XX:+HeapDumpOnOutOfMemoryError 첫 OOM 발생 시 heap dump
- -XX:HeapDumpPath=<경로> dump 저장 위치
- -XX:+ExitOnOutOfMemoryError 첫 OOM에서 JVM을 즉시 종료
- -XX:OnOutOfMemoryError=<명령> 첫 OOM에서 지정한 명령을 실행
heap dump 실습
실습 코드는 저의 GitHub에 공개되어 있습니다.
- https://github.com/choisungwook/portfolio/tree/master/computer_science/java/heapdump
실습 코드는 간단합니다. static 컬렉션은 GC가 회수하지 못하므로, 배열에 1MiB씩 계속 데이터를 넣어 heap이 가득 찰 때까지 쌓습니다.
import java.util.ArrayList;
import java.util.List;
/**
* 메모리 누수를 재현하는 앱.
* static 컬렉션은 GC가 회수하지 못하므로 heap이 가득 찰 때까지 계속 쌓인다.
*/
public class LeakApp {
static final List<byte[]> CACHE = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
System.out.println("pid: " + ProcessHandle.current().pid());
while (true) {
CACHE.add(new byte[1024 * 1024]); // 1MiB씩 누적
if (CACHE.size() % 16 == 0) {
System.out.println("leaked: " + CACHE.size() + " MiB");
}
Thread.sleep(10);
}
}
}
Java 코드는 Docker container로 실행합니다. heap OOM을 빨리 발생시키기 위해 heap 크기를 64MB로 아주 작게 설정했습니다.
FROM eclipse-temurin:21-jdk
WORKDIR /app
COPY app/LeakApp.java .
RUN javac LeakApp.java
CMD ["java", "-Xmx64m", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/dumps/heap.hprof", "LeakApp"]
실행한 지 1초도 안 되어 heap OOM이 발생합니다.
java.lang.OutOfMemoryError

heap dump 파일 분석
heap dump 파일은 hprof라는 바이너리 포맷입니다. 그래서 분석하려면 바이너리를 해석하는 도구가 필요합니다.

heap dump 파일을 분석하는 오픈소스 도구 중 하나는 Eclipse MAT입니다.
- https://eclipse.dev/mat/
MAT에서 Leak Suspects Report를 클릭하면, 어느 구간에서 memory leak이 의심되는지 분석해줍니다.


마무리
정리하면, OOM 순간의 heap dump는 프로세스가 죽은 뒤에 뜨는 것이 아니라, 죽기 직전에 JVM이 직접 남기게 하는 것입니다. 그 스위치가 HeapDumpOnOutOfMemoryError이고, 남은 hprof 파일은 Eclipse MAT 같은 도구로 분석하면 됩니다.
참고자료
'전공영역 공부 기록' 카테고리의 다른 글
| Claude Code 권한 관리 - deny, Auto mode, Skill 자동 호출 제어 (0) | 2026.07.17 |
|---|---|
| LiteLLM QuickStart - guardrail(가드레일) (0) | 2026.07.12 |
| LiteLLM QuickStart - Budget limit(비용제한) (0) | 2026.07.12 |
| LiteLLM QuickStart - 모델 등록하고 호출해보기 (0) | 2026.07.12 |
| RPM/DNF 설치 자동화가 lock 에러로 실패할 수 상황 (0) | 2026.07.05 |