Java로 개발을 하면서 마주할 수 있는 가장 무서운 장애 중 하나로는 메모리 누수로 인해 메모리가 터져버리는 상황이 있다.
사실, 요즘에는 프레임워크나 라이브러리나 IDE에서 이슈가 생길만한 코드가 작성되지 않도록 사전에 방지해주는 게 많아서, 실제로 메모리 누수와 같은 좋은 경험(?)은 겪기가 쉽지는 않다. (일부러 발생시키면 실습 해볼 수 있긴하다.)
메모리 누수가 나는 코드를 수정하기 위해서는 Heapdump를 분석해야하는데, 오늘은 구동 중인 Java 애플리케이션의 Heapdump를 뽑아내서, 간단히 분석해보는 시간을 갖도록 하겠다.
드가자
✍️ 나는 Amazon Linux 2023 서버에서 구동중인 Spring boot 애플리케이션의 Heapdump를 뜨도록 하겠다.
lsof -i tcp:{구동중인 서버의 포트}
jps -v
ps -ef | grep java
서버 애플리케이션이 어떤 PID를 갖고 구동중인지 알기 위해서는 위 명령어emf 중에서 편한 것을 실행해주면 된다.
jps -v
를 실행해보니 내 서버 애플리케이션은 2080로 구동 중이였다.
jmap -dump:format=b,file={파일명}.hprof {서버 애플리케이션의 PID}
위 명령어를 수행하면, 구동중인 애플리케이션의 Heapdump를 뜰 수 있다.
나도 명령어를 수행했고, 이렇게 Heapdump가 잘 생성된 것을 확인할 수 있었다.
scp -i ./{EC2 pem키}.pem {EC2 유저}@{퍼블릭 IP}:/tmp/heapdump.hprof .
로컬에서 위 명령어를 통해서 EC2에 존재하는 Heapdump 파일을 가져오자.
chmod 777
위 명령어를 수행했을 때 Permission denied 에러가 발생한다면, Heapdump 파일의 권한을 다 열어버리자. 🧙ㅋ
Eclipse MAT 홈페이지에서 각자의 OS에 맞게 다운로드를 받자.
설치 후, 실행하면 이렇게 거무죽죽한 화면이 뜬다.
File > Open heap dump
위 버튼을 통해서 EC2에서 가져온 Heapdump를 열어주자.
Heapdump 파일의 import가 완료되면 이렇게 Overview를 보여준다. 원하는 상세 정보들도 볼 수 있다.
Leak suspect 리포트를 클릭하면, 해당 클래스가 메모리 중에서 몇 퍼센트를 차지하고 있는지 보여주면서 메모리 누수가 의심되는 곳들을 보여준다.
이런 식으로 StackTrace도 볼 수 있어서 OOM 에러가 발생한 부분이 어떤 곳인지도 알 수 있을 것이다.
나는 실제로 메모리 누수가 있는 상황이 아니라, 그냥 Heapdump를 생성해서 분석해본 것이므로 유의미한 분석 내용을 확인하긴 어렵다.
참고로 IntelliJ에서 Heapdump 파일을 열어도 분석이 가능하다. MAT보다는 내용이 적지만, 심플하게 필요한 것들을 보여준다.
java -jar -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/heapdumps/ some-application.jar
Java 애플리케이션을 실행할 때, 위와 같은 옵션을 같이 주면, OOM이 발생하면 자동적으로 Heapdump를 생성해준다. OOM이 발생해서 서버가 죽은 상황에서 Heapdump를 생성해야 정확한 분석이 가능하므로 위 옵션은 꼭 사용해보자.