常用的JDK自帶命令行工具
在這里可 以找得到這些工具的列表,雖然官網(wǎng)上免責(zé)聲明為 “The tools described in this section are unsupported and experimental in nature and should be used with that in mind. They might not be available in future JDK versions.”,但實(shí)際上這些工具還是非常有用的,尤其可以站在JVM的角度來(lái)定位問(wèn)題。我在此簡(jiǎn)單羅列一些常用的工具和命令,以及相應(yīng)的執(zhí)行結(jié)果 示例。如果你經(jīng)常和JVM打交道,最好對(duì)這些工具的常用命令熟記。
jstat,這個(gè)工具很強(qiáng)大,可以監(jiān)測(cè)Java虛擬機(jī)GC多方面的狀態(tài),具體參數(shù)含義參見(jiàn)此鏈接:
- ./jstat -gc 84012 1000 3
- S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
- 2112.0 2112.0 0.0 0.0 17024.0 0.0 63872.0 1319.9 21248.0 4728.1 743416 209.646 5 0.046 209.692
- 2112.0 2112.0 0.0 0.0 17024.0 0.0 63872.0 1319.9 21248.0 4728.1 743849 209.755 5 0.046 209.801
- 2112.0 2112.0 0.0 0.0 17024.0 0.0 63872.0 1319.
jmap,這大概是最常用的命令。下面這個(gè)命令不但可以列出類(lèi)的實(shí)例數(shù)量,還有強(qiáng)制進(jìn)行一次full GC的“副作用”,這樣的副作用對(duì)于定位某些問(wèn)題很有幫助,參見(jiàn)《使用堆外內(nèi)存》:
- ./jmap -histo:live 84012
- num #instances #bytes class name
- ----------------------------------------------
- 1: 824 1177656 [B
- 2: 8096 1106672
- ...
使用-heap參數(shù),則可以打印堆的使用情況:
- ./jmap -heap 84012
- Attaching to process ID 84012, please wait...
- Debugger attached successfully.
- Server compiler detected.
- JVM version is 20.65-b04-462
- using parallel threads in the new generation.
- using thread-local object allocation.
- Concurrent Mark-Sweep GC
- Heap Configuration:
- MinHeapFreeRatio = 40
- MaxHeapFreeRatio = 70
- MaxHeapSize = 132120576 (126.0MB)
- NewSize = 21757952 (20.75MB)
- MaxNewSize = 174456832 (166.375MB)
- OldSize = 65404928 (62.375MB)
- NewRatio = 7
- SurvivorRatio = 8
- PermSize = 21757952 (20.75MB)
- MaxPermSize = 85983232 (82.0MB)
- Heap Usage:
- New Generation (Eden + 1 Survivor Space):
- capacity = 19595264 (18.6875MB)
- used = 16785688 (16.008079528808594MB)
- free = 2809576 (2.6794204711914062MB)
- 85.66196403375837% used
- Eden Space:
- capacity = 17432576 (16.625MB)
- used = 16785688 (16.008079528808594MB)
- free = 646888 (0.6169204711914062MB)
- 96.28920017328477% used
- From Space:
- capacity = 2162688 (2.0625MB)
- used = 0 (0.0MB)
- free = 2162688 (2.0625MB)
- 0.0% used
- To Space:
- capacity = 2162688 (2.0625MB)
- used = 0 (0.0MB)
- free = 2162688 (2.0625MB)
- 0.0% used
- concurrent mark-sweep generation:
- capacity = 65404928 (62.375MB)
- used = 1390576 (1.3261566162109375MB)
- free = 64014352 (61.04884338378906MB)
- 2.126102791520541% used
- Perm Generation:
- capacity = 21757952 (20.75MB)
- used = 4852336 (4.6275482177734375MB)
- free = 16905616 (16.122451782226562MB)
- 22.301437194088855% used
使用-permstat參數(shù),查看永久區(qū):
- ./jmap -permstat 84012
- Attaching to process ID 84012, please wait...
- Debugger attached successfully.
- Server compiler detected.
- JVM version is 20.65-b04-462
- 1239 intern Strings occupying 104312 bytes.
- finding class loader instances ..Warning: skipping invalid TLAB for thread t@59779
- Warning: skipping invalid TLAB for thread t@59527
- Warning: skipping invalid TLAB for thread t@59907
- Warning: skipping invalid TLAB for thread t@60163
- Warning: skipping invalid TLAB for thread t@60419
- Warning: skipping invalid TLAB for thread t@60675
- Finding object size using Printezis bits and skipping over...
- done.
- computing per loader stat ..done.
- please wait.. computing liveness...done.
- class_loader classes bytes parent_loader alive? type
- 590 3973048 null live
- 0x00000007f44cace0 0 0 null live sun/misc/Launcher$ExtClassLoader@0x00000007faff8a40
- 0x00000007f44c1478 8 143928 0x00000007f44cace0 live sun/misc/Launcher$AppClassLoader@0x00000007fb056e88
- total = 3 598 4116976 N/A alive=3, dead=0 N/A
把內(nèi)存中的堆dump成一個(gè)鏡像文件:
- ./jmap -dump:live,format=b,file=/Users/xiongyi/Documents/dump.core 84012
#p#
jstack,線程堆棧打印。注意waiting to lock <xxx>在等待鎖,比如進(jìn)入臨界區(qū)時(shí);locked <xxx>表示當(dāng)前同步操作,線程鎖住了某資源;而waiting on <xxx>指的是在同步塊內(nèi),wait方法的執(zhí)行中暫時(shí)地釋放了該鎖的占用,等喚醒的時(shí)候需要重新獲取:
- ./jstack 84012
- 2013-11-11 18:30:35
- Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.65-b04-462 mixed mode):
- "Attach Listener" daemon prio=9 tid=7ff64e206800 nid=0x117782000 waiting on condition [00000000]
- java.lang.Thread.State: RUNNABLE
- "Low Memory Detector" daemon prio=5 tid=7ff64c80f000 nid=0x117c96000 runnable [00000000]
- java.lang.Thread.State: RUNNABLE
- "C2 CompilerThread1" daemon prio=9 tid=7ff64c80e800 nid=0x117b93000 waiting on condition [00000000]
- java.lang.Thread.State: RUNNABLE
- "C2 CompilerThread0" daemon prio=9 tid=7ff64c80d800 nid=0x117a90000 waiting on condition [00000000]
- java.lang.Thread.State: RUNNABLE
- "Signal Dispatcher" daemon prio=9 tid=7ff64c80d000 nid=0x11798d000 runnable [00000000]
- java.lang.Thread.State: RUNNABLE
- "Surrogate Locker Thread (Concurrent GC)" daemon prio=5 tid=7ff64c80c000 nid=0x11788a000 waiting on condition [00000000]
- java.lang.Thread.State: RUNNABLE
- "Finalizer" daemon prio=8 tid=7ff64e13d800 nid=0x11767f000 in Object.wait() [11767e000]
- java.lang.Thread.State: WAITING (on object monitor)
- at java.lang.Object.wait(Native Method)
- - waiting on <7f44c0ed0> (a java.lang.ref.ReferenceQueue$Lock)
- at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- - locked <7f44c0ed0> (a java.lang.ref.ReferenceQueue$Lock)
- at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
- at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:171)
- "Reference Handler" daemon prio=10 tid=7ff64e13c800 nid=0x11757c000 in Object.wait() [11757b000]
- java.lang.Thread.State: WAITING (on object monitor)
- at java.lang.Object.wait(Native Method)
- - waiting on <7f44c0018> (a java.lang.ref.Reference$Lock)
- at java.lang.Object.wait(Object.java:485)
- at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- - locked <7f44c0018> (a java.lang.ref.Reference$Lock)
- "main" prio=5 tid=7ff64c800800 nid=0x10f709000 runnable [10f708000]
- java.lang.Thread.State: RUNNABLE
- at test.Test.main(Test.java:7)
- "VM Thread" prio=9 tid=7ff64e138000 nid=0x117479000 runnable
- "Gang worker#0 (Parallel GC Threads)" prio=9 tid=7ff64e000000 nid=0x112b0f000 runnable
- "Gang worker#1 (Parallel GC Threads)" prio=9 tid=7ff64e001000 nid=0x112c12000 runnable
- "Gang worker#2 (Parallel GC Threads)" prio=9 tid=7ff64e001800 nid=0x112d15000 runnable
- "Gang worker#3 (Parallel GC Threads)" prio=9 tid=7ff64e002000 nid=0x112e18000 runnable
- "Gang worker#4 (Parallel GC Threads)" prio=9 tid=7ff64e002800 nid=0x112f1b000 runnable
- "Gang worker#5 (Parallel GC Threads)" prio=9 tid=7ff64e003800 nid=0x11301e000 runnable
- "Gang worker#6 (Parallel GC Threads)" prio=9 tid=7ff64e004000 nid=0x113121000 runnable
- "Gang worker#7 (Parallel GC Threads)" prio=9 tid=7ff64e004800 nid=0x113224000 runnable
- "Concurrent Mark-Sweep GC Thread" prio=9 tid=7ff64e0e2000 nid=0x1170f0000 runnable
- "Gang worker#0 (Parallel CMS Threads)" prio=9 tid=7ff64e0e0800 nid=0x1166ea000 runnable
- "Gang worker#1 (Parallel CMS Threads)" prio=9 tid=7ff64e0e1800 nid=0x1167ed000 runnable
- "VM Periodic Task Thread" prio=10 tid=7ff64c820800 nid=0x117d99000 waiting on condition
- "Exception Catcher Thread" prio=10 tid=7ff64c801800 nid=0x10f936000 runnable
- JNI global references: 963
jinfo,可以打印JVM執(zhí)行的參數(shù)信息,有一個(gè)非常大的作用在于,部分JVM參數(shù)在執(zhí)行過(guò)程中是可以修改的,請(qǐng)參見(jiàn)這篇《通過(guò)jinfo工具在full GC前后做heap dump》,通過(guò)jinfo改變參數(shù)HeapDumpBeforeFullGC和HeapDumpAfterFullGC,輸出heap dump后,再改回來(lái)。
jhat,可以比對(duì)core文件之間的對(duì)象變化,支持對(duì)象查詢(xún)語(yǔ)言(OQL),請(qǐng)參見(jiàn)這里。
- ./jhat -stack true -refs true -port 8080 -baseline /xxx/dump-baseline.core -debug 1 /Users/xiongyi/Documents/dump-newer.core
javap,用于反編譯class文件,對(duì)于JVM指令集,這里有完整的文檔。
- javap -c -v ./Test.class
- Classfile xxx/Test.class
- Last modified Nov 11, 2013; size 441 bytes
- MD5 checksum 69488187cc8a8f166bc6dd0d517fb4cb
- Compiled from "Test.java"
- public class test.Test
- SourceFile: "Test.java"
- minor version: 0
- major version: 50
- flags: ACC_PUBLIC, ACC_SUPER
- Constant pool:
- #1 = Methodref #6.#16 // java/lang/Object."":()V
- #2 = Integer 1048576
- #3 = Fieldref #17.#18 // java/lang/System.out:Ljava/io/PrintStream;
- #4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/Object;)V
- #5 = Class #21 // test/Test
- #6 = Class #22 // java/lang/Object
- #7 = Utf8
- #8 = Utf8 ()V
- #9 = Utf8 Code
- #10 = Utf8 LineNumberTable
- #11 = Utf8 main
- #12 = Utf8 ([Ljava/lang/String;)V
- #13 = Utf8 StackMapTable
- #14 = Utf8 SourceFile
- #15 = Utf8 Test.java
- #16 = NameAndType #7:#8 // "":()V
- #17 = Class #23 // java/lang/System
- #18 = NameAndType #24:#25 // out:Ljava/io/PrintStream;
- #19 = Class #26 // java/io/PrintStream
- #20 = NameAndType #27:#28 // println:(Ljava/lang/Object;)V
- #21 = Utf8 test/Test
- #22 = Utf8 java/lang/Object
- #23 = Utf8 java/lang/System
- #24 = Utf8 out
- #25 = Utf8 Ljava/io/PrintStream;
- #26 = Utf8 java/io/PrintStream
- #27 = Utf8 println
- #28 = Utf8 (Ljava/lang/Object;)V
- {
- public test.Test();
- flags: ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #1 // Method java/lang/Object."":()V
- 4: return
- LineNumberTable:
- line 4: 0
- public static void main(java.lang.String[]);
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=2, args_size=1
- 0: ldc #2 // int 1048576
- 2: newarray byte
- 4: astore_1
- 5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
- 8: aload_1
- 9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
- 12: goto 0
- LineNumberTable:
- line 7: 0
- line 8: 5
- line 9: 12
- StackMapTable: number_of_entries = 1
- frame_type = 0 /* same */
- }