본문 바로가기
개발/일반

유용한 자바툴 [펌]

by 로그인시러 2017. 3. 23.

들어가며...

얼마전 운영중인 시스템에서 장애가 발생했다. 로그를 보니 OutOfMemoryError가 났다. 그런데 도대체 어디가 문제인지 모르겠다..... 메모리 덤프를 뜨고 어디서 메모리가 세고 있는지 보고 싶지만 엄두가 안난다.
메모리 덤프는 어떻게 떠야 하지? 덤프는 어떻게 보는거지? 뭘 봐야 하는거지?


자바 어플리케이션을 개발하다 보면, 특히 서버/웹 어플리케이션을 개발하다보면 OutOfMemoryError (또는 OutOfMemoryException. 이하, OOME)을 종종 만나게 된다. 그런데 OOME는 보통 개발중에는 발견되지 않고 서비스를 운영하는 도중에 발견되는 경우가 많으며, 이 때 도대체 어디서 문제가 생기는 것인지 발견하기도 상당히 어렵다. 

그래서 각종 모니터링 상용툴을 사용하게 되는데 상용툴을 사용하기에 어려움이 있는 경우가 많고, 쓰더라도 불법으로 쓰게 되는 경우가 보통이다.


자바툴을 사용하자

자바를 처음 시작할 때 반드시 배우는 명령어가 있다. javac, java, javaw (이건 옵션... -_-;;;) 이다.
자바 컴파일러와 인터프리터... javac는 자바 소스코드를 바이트코드로 컴파일해주는 툴이고, java는 컴파일된 자바 바이트코드를 실행하는 툴이다. 모두 알다시피 java 툴은 인터프리터이다.

그런데 JDK 또는 JRE가 설치된 위치에 bin 디렉토리를 보면 javac, java, javaw 들 외에도 상당히 많은 바이너리들이 존재한다. 보통은 JVM에서 그냥 쓰는 녀석들이려니 하고 넘어가지만 만물은 모두 존재이유가 있는 법... -_-;; 이들은 자바 어플리케이션 개발 및 운영시에 상당히 유용하게 사용할 수 있는 각종 툴들이다.

물론 메모리 덤프를 통해 힙 영역에 있는 각종 객체들을 볼 수 있는 툴도 존재한다. 올레~~ /-_-/

이들 중 유용하다고 생각되는 몇개만 뽑아서 정리해보도록 하자. 


1. jps
http://java.sun.com/javase/6/docs/technotes/tools/share/jps.html

jps는 unix 명령어인 ps와 같이 실행중인 자바 프로세스를 보여주는 툴이다. 일반적으로 ps 명령어와 grep 명령어의 조합으로 실행중인 자바 프로세스를 찾을 수도 있지만, jps를 사용하면 좀 더 편하다. (사실.. 말이 편하다는거지 ps 와 grep 으로 찾는게 더 편하다는 사람이 있다면 그것도 좋다.)

옵션없이 실행하면 프로세스 아이디와 클래스명만 보이므로 정보가 매우 부족하다. 
보통 -v 옵션(JVM 파라미터 보임)만 줘도 상당히 좋은 결과를 보여주며, 취향에 따라 -m (메인 메소드의 args 보임)과 -l (전체 패키지명 보임)옵션을 곁들이면 좋다.


2. jmap
http://java.sun.com/javase/6/docs/technotes/tools/share/jmap.html

jmap은 현재 수행중인 자바 어플리케이션의 메모리맵을 보여주는 툴이다. 이 툴을 사용하여 heap 메모리를 덤프떠서 볼 수 있다. 일반적으로 OOME는 heap 영역에서 나는 것이 대부분이므로 이 툴을 사용하는 경우도 아마 heap 메모리 영역을 덤프를 뜨기 위한 것이 대부분일 것이다. 

jmap을 사용하여 heap 메모리 덤프를 뜨는 방법은 다음과 같다.

jmap -dump:<dump-options> pid
또는 
jmap -histo[:live] pid

-dump 옵션을 사용할 때는 보통 -dump:format=b,file=heap.hprof 정도의 옵션만으로 충분하다.

JDK 버전에 따라 제공되는 옵션이 다르므로 jmap -help 명령을 실행한 후에 사용법을 읽어보고, 두개 중 지원되는 옵션을 선택하여 실행하면 된다. 

pid는 ps 명령어를 사용하거나 위에서 본 jps를 사용하여 알아내도록 하자.
 
만약 톰캣과 같이 WAS에서 동작하는 서버 어플리케이션에 jmap을 사용하여 heap 덤프 생성하고자 한다면 -Xmx 옵션값에 주의해야 한다.
만약 -Xmx가 1024m 으로 잡혀있는 WAS에서 OOME 발생 후 jmap으로 heap 덤프를 만들게 되면??
1G가 넘는 덤프파일과 만나게 된다.. -_-;;;;;

보너스~~ heap 덤프를 생성하는 또 다른 방법)
jmap은 runtime에 직접 툴을 실행하여 덤프를 생성해야 한다. 하지만 서비스를 운영하고 있는 경우 OOME가 언제 발생할 줄 알겠는가... OOME가 발생하기까지 눈뜨고 기다렸다가 jmap을 실행하여 덤프를 생성하는건 너무 터무니없다. 이럴 땐 -XX:+HeapDumpOnOutOfMemoryError VM 옵션을 이용하자. 이 옵션을 사용하면 OOME가 발생했을 때 자동으로 java_pid<pid>.hprof 파일명으로 heap 덤프를 생성한다. 또한 -XX:OnOutOfMemoryError=<Command> 옵션을 추가하여 OOME 발생 후 특정 명령어를 수행하도록 할 수도 있다. 주의할 점은 OnOutOfMemoryError 옵션은 JDK 버전 1.4.2 update 12 이후 버전과 6 에서만 동작한다는 점이다. 왜 그런지는 모르겠지만 JDK 5 에서는 해당 옵션을 지원하지 않는다.

이와 같은 VM 추가 옵션에 대해서는 다음의 링크를 참조하면 된다.
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
http://wiki.ex-em.com/index.php/JVM_Options

주의할 점은 -XX 옵션은 Hotspot 옵션으로 각 VM마다 제공할수도 안할수도 있다.


3. jhat
http://java.sun.com/javase/6/docs/technotes/tools/share/jhat.html

jmap으로 heap 메모리 덤프를 생성했으면 이제 메모리를 분석해야 한다. 메모리 덤프 파일은 눈으로 보기 힘드므로 (그래도 굳이 눈으로 보고 싶으면 말리진 않겠다...) 이를 분석하여 쉽게 보여주는 툴이 필요하다.

대표적으로 IBM에서 만든 HeapAnalyzer 가 있지만 라이센스 문제도 있고, 직접 사용해본 결과 덤프 파일의 크기가 매우 큰 경우 HeapAnalyzer에서 OOME가 발생하는 아주 짜증나는 상황에 직면하게 된다. -_-;;;;;;; (물론 jhat도 마찬가지다.)

jhat은 jmap으로 생성된 바이너리 heap 덤프 파일을 분석하여 보여주는 툴이다. jhat을 실행하는 방법은 매우 간단하며 heap 덤프 파일 경로를 주어 jhat을 실행시키면 7000 포트로 분석 결과를 볼 수 있도록 자체 웹서버가 구동된다. 7000 포트가 이미 사용중이면 -port 옵션을 사용하여 포트를 변경할 수 있다.

IBM의 HeapAnalyzer 와 같은 예쁜 GUI를 제공하는 것은 아니지만, 나름 쓸만한 정보를 보여준다.

<jhat 실행 후...>


<각 인스턴스(객체) 별 갯수를 볼 수 있다.. 메모리 누수의 범인은 뉴규~??>



마치며...

이제까지 OOME 발생시 메모리 프로파일링 및 분석에 유용한, 무엇보다 JDK에서 기본으로 제공하는 툴들인 jps, jmap, jhat에 대해 간략하게 살펴봤다. 다만 주의할 점은 이 세가지 툴 모두 Experimental tool 이므로 다음 버전에서 없어져도 할말이 없다는 것이다. 하지만 이런 유용할 툴을 없앨것 같지는 않다.

다음엔 실시간 프로파일링 및 모니터링을 제공하는 관리툴인 jvisualvm 과 jconsole에 대해서 알아볼 것이다.


관련 링크

http://java.sun.com/javase/6/docs/technotes/tools/


관련글
2009/08/21 - [테크 노트 (Tech Note)] - [JavaTool] 유용한 자바툴 - jvisualvm
2009/08/12 - [테크 노트 (Tech Note)] - [JavaTool] 유용한 자바툴 - jconsole


출처: http://tinywolf.tistory.com/103 [붉은늑대의 자바 한모금]

'개발 > 일반' 카테고리의 다른 글

편리한 Junit 사용 moreunit  (0) 2017.04.20
스프트웨어 테스트  (0) 2017.04.19
vi 검색후 색깔 바꾸기  (0) 2017.03.21
scp 사용법 (secure copy)  (0) 2017.03.20
아파치 라이센스  (0) 2017.03.14

댓글