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