기술 탐구/백앤드
(Java) Pod 내에서 jmap를 사용하여 힙 덤프를 떠보자
지혜와 본질을 추구하는 자
2024. 6. 6. 19:32
개요
서비스를 운영하다보면 이유 모르게 OOM이 발생하거나, Heap 영역이 비정상적으로 튀는 일이 종종 있다. 이럴때 Grafana와 같은 지표로 Heap 영역을 추적할 수 있지만, Heap Dump를 통해 메모리 Leak이 발생하는 주된 원인을 찾는것이 가장 저수준으로 문제를 접근하는 방법이다.
들어가며
힙덤프란?
힙덤프(Heap Dump)는 자바 애플리케이션이 실행되는 동안 JVM(Java Virtual Machine)의 힙 메모리에 저장된 객체들의 상태를 캡처한 스냅샷이다.
메모리 사용 상태를 분석하고 메모리 누수 문제를 해결하는 데 매우 유용한 도구이며, 힙덤프를 통해 애플리케이션이 어떤 객체를 메모리에 얼마나 많이 가지고 있는지, 어떤 객체가 가장 많은 메모리를 차지하고 있는지 등을 파악할 수 있다.
힙덤프 방법
덤프할 어플리케이션의 PID를 확인
ps aux | grep java

쓰기 권한이 없을것을 대비하여 /tmp 경로 권한 확인
Pod 내에서 writable 디렉토리를 찾아야 한다. 일반적으로 /tmp 디렉토리는 쓰기 권한이 있다.
ls -ld /tmp
결과: drwxrwxrwt 1 root root 4096 Jun 6 10:05 /tmp
위의 출력에서 drwxrwxrwt는 모든 사용자에게 쓰기 권한이 있음을 나타낸다.

힙덤프 명령어 입력
jmap -dump:format=b,file=/tmp/heapdump.hprof <pid>

로컬로 복사
kubectl cp {name-space}/{pod-name}:/tmp/heapdump.hprof ./heapdump.hprof
인텔리제이로 열기
힙덤프 파일을 사용하기 위해서는 VisualVM 등 여러가지 도구를 사용할 수 있지만 인텔리제이는 자체적으로 힙덤프 파일을 보기 좋게 가공해준다.

결과
주요 지표 설명
지표 | 설명 |
Class | 메모리를 사용하는 클래스의 이름을 나타낸다. |
Count | 각 클래스의 인스턴스 개수를 나타낸다. |
Shallow | 각 객체의 직접적인 메모리 사용량을 나타낸다. |
Retained | 해당 객체가 참조하고 있는 모든 객체들을 포함한 총 메모리 사용량을 나타낸다. |
예시 분석
Class | Count | Shallow | Retained | 분석 |
byte[] | 57981 | 49 MB | 1.11 MB | byte[] 배열이 많은 인스턴스를 가지고 있으며, 큰 메모리 공간을 차지한다. |
java.lang.String | 263848 | 4.44 MB | 13.9 MB | String 객체가 매우 많이 생성되었다. 이는 텍스트 데이터의 사용이 빈번함을 나타낸다. |
java.util.HashMap$Node[] | 83289 | 7.75 MB | 22.42 MB | HashMap의 내부 노드 배열이 많은 메모리를 차지하고 있다. |
상세 분석 방법
- 대상 클래스 확인:
- Class 열을 통해 어떤 클래스가 메모리를 많이 사용하고 있는지 확인한다. 이를 통해 특정 클래스가 메모리 문제의 원인인지 파악할 수 있다.
- 인스턴스 수 분석:
- Count 열을 보고 각 클래스의 인스턴스 수가 적절한지 확인한다. 인스턴스 수가 비정상적으로 많다면 메모리 누수가 발생하고 있을 가능성이 있다.
- 메모리 사용량 분석:
- Shallow와 Retained 열을 비교하여 객체 자체의 메모리 사용량과 해당 객체가 참조하는 모든 메모리 사용량을 파악한다. 특히 Retained 크기가 큰 객체를 집중적으로 분석하는 것이 좋다.
- 메모리 최적화:
- 많이 사용되는 클래스와 객체를 식별한 후, 이들의 생성 및 소멸 주기를 최적화할 방법을 찾는다. 예를 들어, 캐시의 크기를 조정하거나 불필요한 객체 생성을 줄이는 방법을 고려한다.