백엔드 면접 용어 사전
면접 태도·시나리오OutOfMemoryError

OOM

힙이 부족해 발생하는 오류. 누수 의심 지점을 힙 덤프로 확인하는 것이 정석이다.

메모리가 부족해 더 이상 할당할 수 없을 때 발생하는 오류(OutOfMemoryError).

자바에서 — 메시지가 원인을 알려 준다

메시지원인대응
Java heap space힙 부족누수 조사 또는 -Xmx 조정
GC overhead limit exceededGC에 98% 시간을 쓰는데 2% 미만 회수사실상 누수
Metaspace클래스 과다·클래스로더 누수동적 프록시·잦은 재배포 확인
unable to create new native thread스레드 과다풀 크기·ulimit 확인
Direct buffer memoryNIO 다이렉트 버퍼-XX:MaxDirectMemorySize
Requested array size exceeds VM limit비정상적 배열 크기코드 버그

첫 줄만 봐도 어디를 봐야 하는지 알 수 있다.

Error이지 Exception이 아니다

try { … } catch (OutOfMemoryError e) { … }   // 잡지 말 것

Error복구를 기대할 수 없는 상황이다. 잡아서 계속 진행하면 메모리가 없는 상태로 동작해 예측 불가능한 오류가 이어진다.

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/dump.hprof -XX:+ExitOnOutOfMemoryError # 덤프 후 즉시 종료 → 재시작

"덤프를 남기고 죽고, 오케스트레이터가 재시작한다" 가 현대적 대응이다. 살아 있는 척하는 것보다 낫다.

원인 — 누수인가 부족인가

누수 : 안 쓰는 객체가 참조되어 계속 쌓인다

  • 힙을 늘려도 시간만 벌 뿐 결국 터진다 부족 : 실제로 그만큼 필요하다

  • 힙을 늘리거나 처리 방식을 바꾼다

구분 방법

  • Full GC 이후에도 Old 사용률이 계속 우상향 — → 누수
  • 톱니 모양으로 오르내리며 안정적 — → 정상

흔한 누수 패턴

패턴설명
static 컬렉션애플리케이션 생명주기 내내 살아 계속 쌓인다
캐시에 상한 없음Map을 캐시로 쓰면서 제거 정책이 없다
ThreadLocal 미제거스레드 풀에서 remove() 안 하면 스레드가 사는 한 유지
리스너·콜백 미해제등록만 하고 해제 안 함
대량 조회findAll() 로 수백만 건을 한 번에
스트림·커넥션 미close네이티브 자원까지 물고 있다

진단 절차

# 1. 힙 사용 추이
jstat -gcutil <pid> 1000

# 2. 무엇이 많은가
jmap -histo:live <pid> | head -20

# 3. 힙 덤프 (운영 중이면 부하 주의)
jcmd <pid> GC.heap_dump /tmp/heap.hprof

# 4. Eclipse MAT 로 분석
#    - Leak Suspects 리포트
#    - Dominator Tree: 무엇이 메모리를 붙잡고 있나
#    - Path to GC Roots: 왜 회수 안 되나  ← 핵심

Path to GC Roots 가 결정적이다. "이 객체가 왜 살아 있는지"의 참조 사슬을 보여 준다. 대개 여기서 원인이 드러난다.

컨테이너 환경의 함정

① 컨테이너 메모리 인식

옛 JVM은 컨테이너 제한을 못 보고 호스트 메모리 기준으로 힙을 잡아 컨테이너가 OOM Killer에 죽었다. 자바 10+는 인식하지만 명시가 안전하다.

-XX:MaxRAMPercentage=75.0 # 고정값(-Xmx)보다 유연하다

② 힙 외 메모리를 잊는다

컨테이너 메모리 = 힙 + Metaspace + 스레드 스택 + 코드 캐시

    • 다이렉트 버퍼 + GC 구조체 + 네이티브

힙만 딱 맞춰 잡으면 → 컨테이너 OOM Killer(exit 137)에 죽는다

JVM의 OutOfMemoryError와 리눅스 OOM Killer는 다른 것이다. 후자는 로그도 안 남기고 프로세스를 죽인다(dmesg에 기록).

③ 스왑을 끈다 쿠버네티스 기본값이다. 느리게 아픈 것보다 빨리 죽고 재시작하는 편이 낫다.

예방

✅ 캐시에는 반드시 최대 크기와 TTL ✅ 대량 조회는 페이징·스트리밍·커서로 ✅ ThreadLocal 은 finally 에서 remove() ✅ 힙 사용률·GC 시간에 알림 ✅ 부하 테스트로 장시간 운영 시 메모리 추이 확인

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 면접 시나리오·트러블슈팅 — 종합·STAR