Java

자바 메모리 분석을 위한 jmap이란?

강철지그·2014년 5월 21일·조회 37,153

1. 개요

jmap은 JVM을 모니터링 할 수 있는 도구이며, 주요 옵션은 다음과 같다.

  • -dump : JVM Heap 을 덤프 (binary 형식)
  • -finalizerinfo : finalize 를 기다리는 객체 정보
  • -heap : JVM Heap 정보
  • -histo : Heap histogram 정보
  • -permstat : PermGen 정보

2. 사용법

jmap을 실행하면 사용법을 보여준다.

# jmap
Usage:
    jmap [option]
        (to connect to running process)
    jmap [option]
        (to connect to a core file)
    jmap [option] [server_id@]
        (to connect to remote debug server)

where is one of:
                   to print same info as Solaris pmap
    -heap                to print java heap summary
    -histo[:live]        to print histogram of java object heap; if the "live"
                         suboption is specified, only count live objects
    -permstat            to print permanent generation statistics
    -finalizerinfo       to print information on objects awaiting finalization
    -dump: to dump java heap in hprof binary format
                         dump-options:
                           live         dump only live objects; if not specified,
                                        all objects in the heap are dumped.
                           format=b     binary format
                           file=  dump heap to 
                         Example: jmap -dump:live,format=b,file=heap.bin 
    -F                   force. Use with -dump:  or -histo
                         to force a heap dump or histogram when  does not
                         respond. The "live" suboption is not supported
                         in this mode.
    -h | -help           to print this help message
    -J             to pass  directly to the runtime system

3. 실행

그러면 본격적으로 Java 프로세스에 붙여보자. 대상 Java 프로세스는 Java 1.7 버전으로 기동된 Tomcat이다.

# jmap -heap 6854
Attaching to process ID 6854, please wait...
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:622)
	at sun.tools.jmap.JMap.runTool(JMap.java:196)
	at sun.tools.jmap.JMap.main(JMap.java:128)
Caused by: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 23.25-b01. Target VM is 24.51-b03
	at sun.jvm.hotspot.runtime.VM.checkVMVersion(VM.java:234)
	at sun.jvm.hotspot.runtime.VM.(VM.java:297)
	at sun.jvm.hotspot.runtime.VM.initialize(VM.java:367)
	at sun.jvm.hotspot.bugspot.BugSpotAgent.setupVM(BugSpotAgent.java:598)
	at sun.jvm.hotspot.bugspot.BugSpotAgent.go(BugSpotAgent.java:493)
	at sun.jvm.hotspot.bugspot.BugSpotAgent.attach(BugSpotAgent.java:331)
	at sun.jvm.hotspot.tools.Tool.start(Tool.java:163)
	at sun.jvm.hotspot.tools.HeapSummary.main(HeapSummary.java:40)
	... 6 more

4. 오류

그런데 위와 같이 에러가 났다.

확인 결과 이 서버에는 JDK 1.6 버전과 JDK 1.7 버전이 각각 설치되어 있었는데, 내가 사용한 jmap은 JDK 1.6 안에 있던 jmap이었고 (path에 걸려있던 jmap이 JDK 1.6 내 jmap이었음), 연결하려고 했던 Java 프로세스는 JDK 1.7로 올라온 Tomcat이었다.

OS를 설치하면서 기본적으로 OpenJDK가 설치된 가운데 Oracle (Sun) JDK를 또 설치하여 사용하는 경우에 흔히 발생할 수 있는 이슈이다.

그래서 다시 JDK 1.7 내에 포함된 jmap으로 다시 실행하였다. 그리고 아래와 같이 Heap에 대한 자세한 상황을 볼 수 있다.

# /usr/java7/bin/jmap -heap 6854
Attaching to process ID 6854, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.51-b03

using thread-local object allocation.
Mark Sweep Compact GC

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 1073741824 (1024.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 80609280 (76.875MB)
   used     = 2974568 (2.8367691040039062MB)
   free     = 77634712 (74.0382308959961MB)
   3.690106151549797% used
Eden Space:
   capacity = 71696384 (68.375MB)
   used     = 2887136 (2.753387451171875MB)
   free     = 68809248 (65.62161254882812MB)
   4.026892067527422% used
From Space:
   capacity = 8912896 (8.5MB)
   used     = 87432 (0.08338165283203125MB)
   free     = 8825464 (8.416618347167969MB)
   0.9809606215533089% used
To Space:
   capacity = 8912896 (8.5MB)
   used     = 0 (0.0MB)
   free     = 8912896 (8.5MB)
   0.0% used
tenured generation:
   capacity = 178978816 (170.6875MB)
   used     = 42964336 (40.97398376464844MB)
   free     = 136014480 (129.71351623535156MB)
   24.005263282108203% used
Perm Generation:
   capacity = 36831232 (35.125MB)
   used     = 36681104 (34.98182678222656MB)
   free     = 150128 (0.1431732177734375MB)
   99.59238941559164% used

16497 interned Strings occupying 2052408 bytes.

이번에는 permstat으로 확인했다. 시간이 조금 걸린다.

# /engn001/java7/bin/jmap -permstat 6854
Attaching to process ID 6854, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.51-b03
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness............................liveness analysis may be inaccurate ...
class_loader	classes	bytes	parent_loader	alive?	type

	2644	15545072	  null  	live	
0x00000000d241fe60	1	3056	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03634b8	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a6f20	1	3024	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03638e0	1	3040	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fee0	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03635a0	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363860	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a8080	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241ff60	1	3024	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d10bd0f0	1	1880	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d153fcb8	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d1540438	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d07ab170	1	3080	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363428	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0351010	1718	14691072	0x00000000d0362f70	live	org/apache/catalina/loader/StandardClassLoader@0x00000000fb56edb0
0x00000000d0363538	1	3064	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03631f8	1	3024	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d153f8f8	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d1540078	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363278	1	3048	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363720	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a5440	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d141b170	1	3024	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fce0	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03637a0	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03632e0	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363620	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fd60	1	3056	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a5800	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363370	1	3024	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03636a0	1	3040	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363150	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fde0	1	3056	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03638a0	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0362f70	101	1012744	0x00000000d0363088	live	sun/misc/Launcher$AppClassLoader@0x00000000fb00bf48
0x00000000d15a7750	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fe20	1	3056	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03634f8	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a8be8	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a7390	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363820	1	3024	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d07ab0b0	1632	9616080	0x00000000d0351010	live	org/apache/catalina/loader/WebappClassLoader@0x00000000fbca2d98
0x00000000d15a8fa8	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15dd018	1	3024	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fea0	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03635e0	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a65d0	1	3056	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a5078	1	3024	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241ff20	1	3056	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03631b8	1	3064	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d10d0e88	1	3048	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d047ae18	0	0	0x00000000d0362f70	live	java/util/ResourceBundle$RBClassLoader@0x00000000fb0f1bc8
0x00000000d241ffa0	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15a7b10	1	3064	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d21e8218	30	234776	0x00000000d07ab0b0	live	org/apache/jasper/servlet/JasperLoader@0x00000000fc9d10f8
0x00000000d0363760	1	3024	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363238	1	3040	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d15407f8	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03637e0	1	3024	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363320	2	32128	  null  	dead	javax/management/remote/rmi/NoCallStackClassLoader@0x00000000fb4b27b8
0x00000000d0363660	1	3056	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fd20	1	3056	  null  	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d1a65160	1	3024	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d1340078	0	0	0x00000000d0362f70	live	java/net/URLClassLoader@0x00000000fafa00b8
0x00000000d13bb3d0	1	3024	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d03633b0	4	13744	  null  	dead	javax/management/remote/rmi/NoCallStackClassLoader@0x00000000fb4b27b8
0x00000000d13cf990	1	3024	0x00000000d07ab0b0	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d1fc40a0	18	119832	0x00000000d07ab0b0	dead	java/net/URLClassLoader@0x00000000fafa00b8
0x00000000d03636e0	1	3064	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d241fda0	1	3048	0x00000000d0351010	dead	sun/reflect/DelegatingClassLoader@0x00000000fae4f888
0x00000000d0363088	14	94960	  null  	live	sun/misc/Launcher$ExtClassLoader@0x00000000fafa0490

total = 72	6224	41545144	    N/A    	alive=8, dead=64	    N/A

5. 참고자료

좀 더 자세한 사항은 오라클 도큐먼트 http://docs.oracle.com/javase/7/docs/technotes/tools/share/jmap.html 링크를 참고하라.

* 64bit 에서는 jmap -J-d64 -heap pid 와 같이 추가 옵션을 주어야 한다고 하는데, 나는 옵션을 주지 않아도 되었다.

* 향후 버전에서는 지원되지 않을 수 있다고 한다.


6. 버그

jmap 관련 버그도 있다.

JDK-6966967 : G1: SA: jmap and jstack do not work (http://bugs.java.com/view_bug.do?bug_id=6966967)


7. 바이너리 코어

상황에 따라 jmap으로 덤프를 획득하지 못하는 경우가 있다. 이 때는 OS 바이너리 덤프로부터 힙 덤프를 추출할 수 있다. (HotSpot JVM 한정)

바이너리 덤프는 다음과 같이 생성할 수 있다. gcore에 대해서는 더 자세히 알아보자.

  • AIX : $ gencore [pid] [파일명]
  • Linux : $ gcore -o [파일명] [pid]
  • 윈도우 : 작업관리자 -> 프로세스 -> 우클릭 -> 덤프 파일 생성

바이너리 덤프가 생성되면 다음과 같은 형식으로 힙 덤프를 추출한다.

jmap -dump:format=b,file=[파일명] [자바경로] [바이너리덤프]

예는 다음과 같다.

$ jmap -dump:format=b,file=myDump.hprof /usr/bin/java core.10883

댓글 4

로그인 후 댓글을 남길 수 있습니다.

  • 몽상가몽상가· 2014년 5월 21일
    좋은 정보 감사합니다. 근데 스크롤의 압박이...
  • 강철지그강철지그· 2014년 5월 23일
    MaxNewSize = 17592186044415 MB 는 무엇을 의미하는걸까요?
  • 열린기술자열린기술자· 2014년 5월 26일
    JDK-6792386 : SA: jmap wrong output for MaxNewSize Problem 1:. Java does not support unsinged long (64bit) so it is difficult to print the max value of unsigned long (64bit) in java so we do not print for this case or any value which is greater than the max value of signed long (64bit). Problem 2: If the MaxNewSize is not set in command line then vm uses the max value of unsigned long (64bit) for MaxNewSize. SA just reads the value of MaxNewSize variable and prints it. Whatever is set in vm you see it here.
  • unnamedunnamed· 2014년 9월 4일
    감사합니다