애플리케이션이 아무 에러 로그도 안 남기고 갑자기 종료됐다면, 커널의 OOM Killer가 메모리 부족 상황에서 그 프로세스를 강제로 죽였을 가능성이 큽니다. 애플리케이션 로그만 보면 영원히 못 찾습니다. 커널 로그를 봐야 합니다.
1단계 — OOM이 정말 있었나 (dmesg)
로컬 터미널
dmesg -T | grep -i -E "out of memory|killed process|oom"
전형적인 흔적은 이렇게 찍힙니다.
OUTPUT
Out of memory: Killed process 24871 (java) total-vm:8123456kB,
anon-rss:6012345kB, file-rss:0kB, oom_score_adj:0
Killed process에 죽은 PID와 프로세스 이름이, anon-rss에 그 프로세스가 쓰던 실제 메모리가 찍힙니다. 시각은 dmesg -T의 타임스탬프로 애플리케이션이 사라진 시점과 맞춰 봅니다.
2단계 — 왜 OOM이 났나
OOM은 두 가지 그림으로 나뉩니다.
로컬 터미널
free -h # 전체 메모리·스왑 여유
cat /proc/meminfo # 상세
스왑까지 다 찼는지, 아니면 특정 cgroup(컨테이너) 한계에 걸렸는지를 가립니다. 도커/쿠버네티스라면 호스트는 멀쩡한데 컨테이너 메모리 limit에 걸려 OOM 나는 경우가 흔합니다.
로컬 터미널
# 컨테이너가 limit에 걸려 죽었는지
dmesg -T | grep -i "memory cgroup"
docker inspect <container> | grep -i oom # OOMKilled: true
원인별 해결
- 메모리 누수: 시간이 지날수록 RSS가 우상향 → 애플리케이션 힙/누수 점검, 재시작은 임시방편
- 컨테이너 limit 과소 설정: 호스트는 여유 있는데 cgroup limit 초과 → limit 상향 또는 JVM
-Xmx를 limit보다 낮게 - 스왑 부재 + 순간 피크: 배치·빌드가 순간적으로 메모리를 몰아 씀 → 작업 분할 또는 적정 스왑 확보
- 엉뚱한 프로세스가 죽음: OOM Killer는
oom_score가 높은(메모리 많이 쓰는) 프로세스를 고름 → 꼭 살려야 할 프로세스는 보호
핵심 데몬을 OOM 대상에서 빼려면 oom_score_adj를 낮춥니다.
로컬 터미널
echo -1000 > /proc/<PID>/oom_score_adj # 이 프로세스는 마지막에 죽임
cat /proc/<PID>/oom_score # 현재 점수 확인
체크리스트
로컬 터미널
dmesg -T | grep -i "out of memory" # OOM 발생·죽은 PID 확인
free -h # 전체 메모리·스왑 여유
dmesg -T | grep -i "memory cgroup" # 컨테이너 limit OOM 여부
cat /proc/<PID>/oom_score # 위험 프로세스 점수
OOM Killer의 동작과 cgroup 메모리 한계, dmesg 읽는 감각을 직접 실습으로 익히려면 리눅스 트랙에서 회원가입 없이 무료로 시작할 수 있습니다.