OOM 장애 해결기

dev.hyjang·2026년 6월 10일

장애 현상

  • 운영 중인 Tomcat WAS가 예기치 않게 종료
  • 로그를 확인한 결과 java.lang.OutOfMemoryError: Direct buffer memory 발생

Direct Buffer란?

JVM은 Heap 영역 외에도 다양한 메모리 영역을 사용

  • Heap : 객체 저장 영역
  • Metaspace : 클래스 메타데이터 저장 영역
  • Thread Stack : 스레드 실행 정보 저장 영역
  • Code Cache : JIT 컴파일 코드 저장 영역
  • Direct Buffer : JVM 외부 Native Memory 사용 영역
  • Direct Buffer는 주로 NIO 기반 네트워크 통신이나 파일 입출력 시 사용됨
  • 일반 Heap 객체와 달리 OS 메모리를 직접 사용하기 때문에 I/O 성능상 이점이 있지만, 과도하게 사용될 경우 별도의 OOM이 발생할 수 있음

원인 분석

당시 시스템에는 MIP(Microsoft Information Protection) 기능이 신규 적용된 상태였음
암호화 과정에서 MIP API와 지속적으로 통신이 발생

장애 흐름은 다음과 같았음.

대량 문서 암호화
    ↓
MIP API 네트워크 통신 증가
    ↓
Direct Buffer 사용량 급증
    ↓
Native Memory 고갈
    ↓
java.lang.OutOfMemoryError: Direct buffer memory
    ↓
Tomcat 종료
  • MIP API 호출 과정에서 Direct Buffer 사용량이 증가했고, JVM이 사용할 수 있는 Native Memory 한계를 초과하면서 OOM이 발생함.

JVM 메모리 구조 분석

OOM이라고 해서 항상 Heap Memory 부족을 의미하는 것은 아님.
JVM 프로세스는 다음과 같은 메모리 영역을 함께 사용함.

JVM Memory
├── Heap
│   └── Java 객체 저장
│
├── Non-Heap
│   ├── Metaspace
│   ├── Code Cache
│   └── Direct Buffer
│
└── Thread Stack
  • 운영 중인 애플리케이션이 네트워크 통신이나 파일 처리를 많이 수행한다면 Heap보다 Direct Buffer가 먼저 한계에 도달할 수도 있음.

해결 및 조치

  • 장애 원인 분석 후 JVM 메모리 구조를 전반적으로 재설계함.
  • 기존에는 Heap 중심으로만 관리하고 있었으나, Native Memory 영역까지 고려하여 JVM 옵션을 보완함.
-Xms8192m
-Xmx8192m
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:MaxDirectMemorySize=1024m
-Xss512k
-XX:ReservedCodeCacheSize=256m

특히 Direct Buffer 사용량을 명시적으로 관리하기 위해 다음 옵션을 추가함.

-XX:MaxDirectMemorySize=1024m
  • 또한 Metaspace, Thread Stack, Code Cache 영역까지 포함하여 JVM 전체 메모리 사용량을 재산정함.

결과

  • 설정 적용 이후 동일한 대량 문서 암호화 작업을 수행해도 Direct Buffer Memory OOM은 재발하지 않았음!!!
  • 메모리 사용량 역시 예측 가능한 범위 내에서 유지되었고, 운영 안정성이 향상됨.

회고

  • NIO 기반 네트워크 통신 사용
  • 대용량 파일 처리
  • 외부 API 호출 빈도가 높은 서비스
  • 대규모 배치 작업
    을 할 때는 JVM 메모리 구조를 설정하자.

참고

Direct Buffer Memory OOM 로그 예시

java.lang.OutOfMemoryError: Direct buffer memory
	at java.nio.Bits.reserveMemory(Bits.java:695)
	at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
	at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)

해당 로그가 발생한다면 Heap Memory가 아닌 Native Memory 영역의 사용량도 함께 확인해 보는 것이 좋음.

profile
낭만감자

0개의 댓글