JVM heap은 멀쩡한데 왜 메모리가 터질까? — Docker 환경 네이티브 메모리 삽질기 (Part 2)
백엔드
JVM heap은 멀쩡한데 왜 메모리가 터질까? — Docker 환경 네이티브 메모리 삽질기 (Part 2)
두줄요약
JVM 힙은 정상인데 컨테이너가 OOMKilled되는 원인을 네이티브 메모리에서 추적했습니다. 스트림 close 누락과 zlib Inflater 버퍼가 핵심이었고, 도구 조합으로 범인을 찾았습니다.
문제 상황
- JVM 힙은 정상인데 Docker 컨테이너 RSS가 계속 증가해 OOMKilled 되는 현상
- NMT로도 설명되지 않는 힙 밖 네이티브 메모리 갭 발생
- getResourceAsStream 사용 시 닫지 않은 Inflater가 네이티브 버퍼를 오래 점유하는 구조
원인 분석
- JAR 내부 압축 리소스 읽기 과정에서 java.util.zip.Inflater 생성
- 스트림 close 누락으로 zlib 네이티브 메모리 반납 지연
- 힙, NMT, RSS가 서로 다른 관점을 보여 추적 사각지대 발생
해결 방법
- jemalloc과 jeprof로 네이티브 malloc 할당 경로 추적
- async-profiler의 alloc 이벤트로 Inflater를 유발한 자바 호출 경로 확인
- 스트림 close 또는 try-with-resources 적용으로 네이티브 자원 즉시 해제
