힙 덤프(Heap Dump) 추출 방법 및 MAT(Memory Analyzer Tool) 활용법

지난 포스팅에서는 VisualVM과 JConsole을 이용해 실시간으로 서버의 건강 상태를 점검하는 방법을 알아보았습니다. 하지만 서버가 이미 OutOfMemoryError(OOM)를 뱉으며 장렬하게 전사해 버렸다면, 실시간 모니터링 도구는 더 이상 소용이 없습니다.

이때 개발자가 서버의 사망 원인(메모리 누수)을 부검하기 위해 반드시 확보해야 하는 결정적 증거가 바로 힙 덤프(Heap Dump)입니다. 이번 글에서는 운영 서버에서 안전하게 힙 덤프를 추출하는 방법과, 추출한 대용량 파일을 분석하여 메모리 누수의 진범을 찾아내는 강력한 도구인 MAT(Memory Analyzer Tool)의 활용법을 완벽히 정리해 보겠습니다.

1. 힙 덤프(Heap Dump)란 무엇인가?

힙 덤프는 특정 시점에 JVM 힙(Heap) 메모리에 올라가 있는 모든 객체(Object)의 상태, 클래스 정보, 그리고 객체 간의 참조(Reference) 관계를 바이트 형태로 기록한 스냅샷 파일입니다.

보통 .hprof 확장자를 가지며, 서버에 할당된 힙 메모리 사이즈(예: 4GB)와 거의 동일한 크기로 생성됩니다. 이 파일을 전용 분석 도구로 열어보면, 어떤 클래스의 인스턴스가 비정상적으로 많이 생성되었는지, 그리고 그 인스턴스들을 누가 참조하고 있어서 가비지 컬렉터(GC)가 지우지 못하고 있는지 정확하게 추적할 수 있습니다.

2. 실무 운영 서버: 힙 덤프 추출하는 2가지 정석

운영 환경에서 힙 덤프를 얻는 방법은 크게 ‘자동’과 ‘수동’으로 나뉩니다. 실무에서는 첫 번째 자동 추출 방식을 반드시 기본 옵션으로 설정해야 합니다.

  • 1) OOM 발생 시 자동 추출 (필수 JVM 옵션): 서버가 언제 OOM으로 죽을지 사람이 24시간 감시할 수는 없습니다. 따라서 JVM이 기동 될 때 아래의 두 가지 옵션을 반드시 넣어주어야 합니다. 이 옵션이 있으면 서버가 OOM으로 다운되는 순간, JVM이 죽기 직전의 메모리 상태를 파일로 남겨놓고 장렬히 전사합니다. -XX:+HeapDumpOnOutOfMemoryError (OOM 발생 시 덤프 생성 활성화) -XX:HeapDumpPath=/log/tomcat/dump/ (덤프 파일이 저장될 경로 지정)
  • 2) 수동 추출 (jcmd 또는 jmap 활용): OOM이 발생하진 않았지만 메모리 사용량이 비정상적으로 높아 선제적인 분석이 필요할 때 사용합니다. Java 8 이후 권장되는 jcmd 명령어를 사용합니다.

    jcmd <PID> GC.heap_dump /path/to/dump.hprof

    ⚠️주의 : 수동 추출 시 수 초간 서버에 Stop-The-World가 발생하므로 트래픽이 적은 새벽 시간에 수행해야 합니다.

3. Eclipse MAT(Memory Analyzer Tool)를 활용한 메모리 누수 분석

수 기가바이트(GB)에 달하는 방대한 덤프 파일을 분석하기 위해 이클립스 재단에서 만든 오픈소스 툴인 Eclipse MAT를 사용합니다. MAT는 메모리를 낭비하는 원인을 시각적이고 직관적으로 찾아주는 최고의 분석 도구입니다.

  • Leak Suspects Report (누수 의심 보고서): MAT에서 덤프 파일을 열면 가장 먼저 실행해야 할 마법 같은 기능입니다. MAT가 스스로 덤프 파일을 분석하여, “전체 메모리의 60%를 A라는 스레드의 B 객체가 차지하고 있어 메모리 누수가 의심됩니다”라는 형태의 보고서를 화려한 파이 차트(Pie Chart)와 함께 자동으로 생성해 줍니다.
  • Shallow Heap vs Retained Heap의 이해: MAT 분석의 핵심 개념입니다.
    • Shallow Heap: 객체 그 자체가 차지하는 순수 메모리 크기입니다. (일반적으로 크기가 매우 작습니다.)
    • Retained Heap (중요): 이 객체가 가비지 컬렉션(GC)으로 삭제될 때, 함께 메모리에서 해제될 수 있는 연관 객체들의 총합입니다. 메모리 누수를 잡으려면 얕은 크기(Shallow)가 아니라, 이 Retained Heap 사이즈가 비정상적으로 큰 거대한 루트(Root) 객체를 찾아내야 합니다.
  • Dominator Tree (지배자 트리): Retained Heap 크기를 기준으로 객체들을 내림차순 정렬하여 보여주는 뷰입니다. 이 트리의 최상단에 위치한 객체부터 역추적(Path to GC Roots)해 나가면, 개발자가 컬렉션(List, Map)에 데이터를 넣기만 하고 빼지 않은 코드의 정확한 위치를 검거할 수 있습니다.

결론: 감이 아닌 증거로 디버깅하라

메모리 누수는 코드를 눈으로만 봐서는 절대 찾을 수 없습니다. OOM 자동 추출 옵션을 서버에 적용해 두는 것은 자동차의 블랙박스를 켜두는 것과 같습니다. 사고(OOM)가 났을 때 남겨진 힙 덤프를 MAT로 분석하여 정확한 증거(Retained Heap)를 기반으로 코드를 수정하는 것이 진정한 시니어 개발자의 문제 해결 방식입니다.

내장 도구들을 활용한 디버깅 방법을 알아보았으니, 다음 포스팅에서는 엔터프라이즈 환경에서 통합적인 성능 관리를 위해 사용하는 상용 모니터링 시스템, ‘APM(Application Performance Management) 툴의 주요 메트릭 해석 가이드’에 대해 종합적으로 살펴보겠습니다.

댓글 남기기