Java Heap Dump 를 이용한 문제 해결

개발이야기|2021. 5. 27. 23:13

+ 문제 발생

개인적으로 사용하고 있는 Spring 웹 서버가 하나 있다.

언제부터인가 Out Of Memory Error 가 발생하며 웹 서버가 죽어 있는 것이였다. 갑자기 애플리케이션이 죽어 버리는 것은 아니고, 몇 일이 지나서야 이런 현상이 발생했다.

 

가벼운 애플리케이션이고, JVM 옵션으로 -Xms1024m -Xmx2048m 를 할당했기 때문에 메모리 부족 오류는 아닐 것이다라는 생각이였다.

혹시 내 애플리케이션이 메모리를 많이 사용하는지를 검증하기 위해서 모니터링 툴을 연동해 보기로 했다.

Spring Boot Admin을 이용하기로 했고, 셋팅을 한 후 추이를 지켜보았다.

 

[웹 서버 구동 즉시 현황]

Heap 메모리 사용률이 600 MB 밖에 안된다.

[웹 서버 구동 후 1일 23시간이 지난 후]

메모리 사용률이 1.5 GB 이나 된다.

웹 서버에서는 현재 아무런 동작을 하고 있지 않는데 1.5 GB 의 heap 영역을 사용하고 있다라는 것은 어딘가에 문제가 있다는 것이다.

 

+ Heap Dump 파일 생성하기

메모리 누수가 있다는 판단하에 Heap Dump를 뜨게 됐다.

 

process id 값을 찾는다.

$ ps -df | grep java
user1234  12588     1  0 May23 ?        00:11:00 /var/packages/Java8/target/j2sdk-image/bin/java -jar -Xms128m -Xmx256m spring_boot_admin.jar
user1234  26890     1 20 22:52 pts/4    00:01:34 /var/packages/Java8/target/j2sdk-image/bin/java -jar -Xms1024m -Xmx2048m -Dspring.profiles.active=live my_application.jar

 

process id 값을 확인한 후 heap dump 를 뜬다.

$ jmap -dump:format=b,file=heap.dump 26890

heap.dump 파일이 생성된다.

내가 생성한 heap.dump 파일의 용량은 2.2Gbyte 이다.

서버에서 생성한 heap.dump 파일을 분석하기 위해서 로컬 PC로 다운 받는다.

 

 

+ Heap Dump 분석을 위한 툴 설치

heap dump 분석툴로는 Eclipse Memory Analyzer를 사용한다.

https://www.eclipse.org/mat/downloads.php 에서 다운로드 받는다.

툴을 실행하기에 앞서 MemoryAnalyzer.ini 파일을 수정해줘야 한다.

Eclipse Memory Analyzer도 java 기반으로 동작하기 때문에 heap 사이즈를 지정할 수 있다. 대부분 heap.dump 파일이 용량이 큼으로 Xms, Xmx 사이즈를 넉넉하게 주도록 하자.

-startup
plugins/org.eclipse.equinox.launcher_1.5.700.v20200207-2156.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.1100.v20190907-0426
-vmargs
-Xms2g
-Xmx4g

실행 화면

 

 

+ Heap Dump 분석하기

가장 중요한 부분이다.

Eclipse Memory Analyzer 프로그램에서 heap dump 파일을 열어보자.

heap dump 파일 사이즈가 크기 때문에 로드하는데 시간이 걸린다.

 

결과가 나왔다.

오마이갓~

메모리 릭이 의심되는 두 가지 문제를 찾았다.

각각의 문제들로 인한 메모리 점유율이 1.6 GB 나 된다.

정확히 문제가 뭔지 확인해 본다.

JS executor for com.gargoylesoftware.htmlunit.WebClient@1fb13b1d 객체의 로컬 변수에서 821,142,568 bytes 를 사용하고 있다고 나온다. 대략 783 Mbyte 이다.

 

Problem Suspect 2의 문제도 Problem Suspect 1번과 동일하다.

문제는 WebClient 객체에서 발생하고 있는 것이였다.

WebClient 클래스는 내가 구현한 것이 아닌 오픈소스로 제공하고 있는 클래스 파일이다.

오픈소스로 제공하고 있는 라이브러리이기도 하고, 많은 사람들이 사용하기 때문에 버그는 아닐 것이다라고 예상했다.

그렇다면 내가 사용을 잘못하고 있다라는 점인데.. 이 부분에 대해서 조사를 해봐야 하겠다.

 

 

+ 메모리 릭 발생 원인 찾기

stackoverflow에 htmlunit memory leak 을 검색해 보니 많은 정보가 나왔다.

WebClient 를 사용하고 난 뒤에는 close 메서드를 호출해야 한다라는 점이다.

htmlunit 라이브러리를 이용하면 javascript 가 동작한 후의 HTML 결과물을 가져올 수 있다.이때 javascript 가 계속 동작하게 되면서 문제가 발생되는 듯 하다.

 

웹 페이지 스크래핑 이후에 WebClient 의 close() 메서드가 호출되게 코드를 수정한 후 배포하였다.

 

 

+ Heap Dump 다시 생성하기

메모리 릭이 발생되는 문제를 수정하고, 몇 시간이 지난 후에 다시 heap dump를 생성했다.

문제가 해결됐다. 더이상 WebClient 객체에서 메모리 릭이 발생하지 않는다.

 

메모리 사용량도 엄청 줄었다.

 

 

+ 결론

heap dump를 통해서 메모리 누수가 발생하고 있다는 것을 알게 되었고, 그것을 해결하여 서비스를 정상화 시켰다.

이처럼 문제를 찾는데 있어 heap dump 분석은 중요하다.

 

서비스를 오픈하기 전에 heap dump를 여러 개 생성하여 분석해 보는 것도 개발자에게는 좋은 습관중에 하나가 될 것이리라 생각한다.

'개발이야기' 카테고리의 다른 글

REST API 설계 시 코드성 값 (Integer vs String)  (0) 2023.05.17
if 지옥에 빠지다  (0) 2023.05.13
비효율의 숙달화  (448) 2023.05.10
Github webhook 302 오류  (0) 2021.05.20
Mail health check failed 오류  (2) 2021.05.19
코드 가독성에 대한 이야기  (2) 2021.02.27

댓글()