一、JDK命令行工具簡介
所有的java開發人員都知道JDK的bin目錄下存放着編譯java需要的javac,以及運行java程序需要的java這兩個命令工具,但是很多人並沒有注意到,其實除了這兩個工具,該目錄下還有很多工具,這些工具其實為我們提供了很多方便且強大的功能,windows7系統64位jdk1.7/bin目錄下部分截圖:

下面是命令行監控的主要工具和用途:
名稱 | 作用 |
jps | JVM Process Status Tool,現實指定系統內所有的HotSpot虛擬機進程 |
jstat | JVM Statistics Monitoring Tool,用於收集Hotspot虛擬機各個方面的運行參數 |
jinfo | Configuration Info for Java,現實虛擬機配置信息 |
jmap | Memory map for java,生成虛擬機的內存轉儲快照 |
jhat | JVM heap Dunp Browser,用於分析heapdump文件,他會建立一個HTTP/HTML服務,讓用戶可通過瀏覽器查看 |
jstack | Stack Track for java ,顯示虛擬機線程快照 |
1、jps
jps用來查看基於HotSpot的JVM里面中,所有具有訪問權限的Java進程的具體狀態, 包括進程ID,進程啟動的路徑及啟動參數等等,與unix上的ps類似,只不過jps是用來顯示java進程,可以把jps理解為ps的一個子集。 使用jps時,如果沒有指定hostid,它只會顯示本地環境中所有的Java進程;如果指定了hostid,它就會顯示指定hostid上面的java進程,不過這需要遠程服務上開啟了jstatd服務,可以參看前面的jstatd章節來啟動jstad服務。
命令格式 :jps [ options ] [ hostid ]
參數說明 :
-q 忽略輸出的類名、Jar名以及傳遞給main方法的參數,只輸出pid。
-m 輸出傳遞給main方法的參數,如果是內嵌的JVM則輸出為null。
-l 輸出應用程序主類的完整包名,或者是應用程序JAR文件的完整路徑。
-v 輸出傳給JVM的參數。
-V 輸出通過標記的文件傳遞給JVM的參數(.hotspotrc文件,或者是通過參數-XX:Flags=<filename>指定的文件)。
-J 用於傳遞jvm選項到由javac調用的java加載器中,例如,“-J-Xms48m”將把啟動內存設置為48M,使用-J選項可以非常方便的向基於Java的開發的底層虛擬機應用程序傳遞參數。下面樣例均在linux的jdk1.7下測試。
使用樣例:
[root@tools138 ~]# jps
2897 Bootstrap
22558 Jps
[root@tools138 ~]# jps -l
2897 org.apache.catalina.startup.Bootstrap
22568 sun.tools.jps.Jps
[root@tools138 ~]# jps -v
2897 Bootstrap -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp
22578 Jps -Denv.class.path=/usr/java/jdk1.7.0/lib -Dapplication.home=/usr/java/jdk1.7.0 -Xms8m
2、jstat
Jstat用於監控基於HotSpot的JVM,對其堆的使用情況進行實時的命令行的統計,使用jstat我們可以對指定的JVM做如下監控:
- 類的加載及卸載情況
- 查看新生代、老生代及持久代的容量及使用情況
- 查看新生代、老生代及持久代的垃圾收集情況,包括垃圾回收的次數及垃圾回收所占用的時間
- 查看新生代中Eden區及Survior區中容量及分配情況等
jstat工具特別強大,它有眾多的可選項,通過提供多種不同的監控維度,使我們可以從不同的維度來了解到當前JVM堆的使用情況。詳細查看堆內各個部分的使用量,使用的時候必須加上待統計的Java進程號,可選的不同維度參數以及可選的統計頻率參數。
命令格式:
jstat [ option vmid [interval][s|ms][count]]
option 參數如下面表格
Option Displays...class | 用於查看類加載情況的統計 |
compiler | 用於查看HotSpot中即時編譯器編譯情況的統計 |
gc | 用於查看JVM中堆的垃圾收集情況的統計 |
gccapacity | 用於查看新生代、老生代及持久代的存儲容量情況 |
gccause | 用於查看垃圾收集的統計情況(這個和-gcutil選項一樣),如果有發生垃圾收集,它還會顯示最后一次及當前正在發生垃圾收集的原因。 |
gcnew | 用於查看新生代垃圾收集的情況 |
gcnewcapacity | 用於查看新生代的存儲容量情況 |
gcold | 用於查看老生代及持久代發生GC的情況 |
gcoldcapacity | 用於查看老生代的容量 |
gcpermcapacity | 用於查看持久代的容量 |
gcutil | 用於查看新生代、老生代及持代垃圾收集的情況 |
printcompilation | HotSpot編譯方法的統計 |
使用樣例:
[root@tools138 ~]# jstat -class 2897
Loaded Bytes Unloaded Bytes Time
67431 113866.2 59850 98607.5 1884.07
[root@tools138 ~]# jstat -compiler 2897
Compiled Failed Invalid Time FailedType FailedMethod
3782 1 0 507.88 1 org/apache/tomcat/util/IntrospectionUtils setProperty

表示查詢系統進程為2897的java程序gc,每100毫秒查詢一次,一共查詢十次,顯示結果每列的含義如下:
列名 說明
其他以gc開始的結果列跟gc選項結果列基本一樣,這里不一一列舉了。
S0C | 新生代中Survivor space中S0當前容量的大小(KB) |
S1C | 新生代中Survivor space中S1當前容量的大小(KB) |
S0U | 新生代中Survivor space中S0容量使用的大小(KB) |
S1U | 新生代中Survivor space中S1容量使用的大小(KB) |
EC | Eden space當前容量的大小(KB) |
EU | Eden space容量使用的大小(KB) |
OC | Old space當前容量的大小(KB) |
OU | Old space使用容量的大小(KB) |
PC | Permanent space當前容量的大小(KB) |
PU | Permanent space使用容量的大小(KB) |
YGC | 從應用程序啟動到采樣時發生 Young GC 的次數 |
YGCT | 從應用程序啟動到采樣時 Young GC 所用的時間(秒) |
FGC | 從應用程序啟動到采樣時發生 Full GC 的次數 |
FGCT | 從應用程序啟動到采樣時 Full GC 所用的時間(秒) |
GCT | T從應用程序啟動到采樣時用於垃圾回收的總時間(單位秒),它的值等於YGC+FGC |
3、jinfo
jinfo可以輸出並修改運行時的java 進程的opts。用處比較簡單,用於輸出JAVA系統參數及命令行參數。
命令格式:
jinfo [option] pid
使用樣例:
[root@tools138 ~]# jinfo -flag MaxNewSize 2897
-XX:MaxNewSize=18446744073709486080
4、jmap
jmap用於生成堆轉儲快照(一般稱為heapdump或者dump文件)。當然也可其他方法比如加參數-XX:+HeapDumpOnOutOfMemoryError參數,在虛擬機OOM異常的之后自動生成dump文件,也可以通過-XX:+HeapDumpOnCtrlBreak參數則可以使用Ctrl+Break鍵讓虛擬機生成dump文件。在前文《 JAVA虛擬機之3:CMS垃圾收集器》測試中就有生成。dump文件生成后可借助jha、MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer來對dump分析。jmap不僅能獲取dump還可以查詢finalize執行隊列,java堆和永久代詳細信息,空間使用率,當前用的是什么收集器等。
jmap -J-d64 -heap pid
命令格式:
jmap [ option ] pid
參數說明:
-dump:[live,]format=b,file=<filename> 使用hprof二進制形式,輸出jvm的heap內容到文件=. live子選項是可選的,假如指定live選項,那么只輸出活的對象到文件.
-finalizerinfo 打印正等候回收的對象的信息.
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情況.
-histo[:live] 打印每個class的實例數目,內存占用,類全名信息. VM的內部類名字開頭會加上前綴”*”. 如果live子參數加上后,只統計活的對象數量.
-permstat 打印classload和jvm heap長久層的信息. 包含每個classloader的名字,活潑性,地址,父classloader和加載的class數量. 另外,內部String的數量和占用內存數也會打印出來.
-F 強迫.在pid沒有相應的時候使用-dump或者-histo參數. 在這個模式下,live子參數無效.
使用樣例:
jmap -dump:format=b,file=eclipse.bin
[root@tools138 ~]# jmap -dump:format=b,file=eclipse.bin 2897
Dumping heap to /root/eclipse.bin ...
Heap dump file created
5、jhat
jhat是sun提供的dump分析工具,上面講過分析dump的工具還有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer等,一般這個命令不太用到,是因為分析dump是個既耗時又耗機器資源的過程,第二個原因是這個工具比較簡陋,沒有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer這些專業和強大。
命令格式:
jhat file
使用樣例:
防止影響服務,所以在本地windows下使用,先導出dump文件
C:\Users\hz>jmap -dump:format=b,file=test.bin 5152
Dumping heap to C:\Users\hz\test.bin ...
Heap dump file created
然后分析:
C:\Users\hz>jhat test.bin
Reading from test.bin...
Dump file created Wed Dec 30 13:29:19 CST 2015
Snapshot read, resolving...
Resolving 9692 objects...
Chasing references, expect 1 dots.
Eliminating duplicate references.
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
載在瀏覽器中輸入localhost:7000查看結果,如下圖。

6、jstack
jstack用於打印出給定的java進程ID或core file或遠程調試服務的Java堆棧信息,如果是在64位機器上,需要指定選項"-J-d64",Windows的jstack使用方式只支持以下的這種方式:
如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發生問題。另外,jstack工具還可以附屬到正在運行的java程序中,看到當時運行的java程序的java stack和native stack的信息, 如果現在運行的java程序呈現hung的狀態,jstack是非常有用的。
命令格式 :
jstack [ option ] pid
參數說明:
-F當’jstack [-l] pid’沒有相應的時候強制打印棧信息
-l長列表. 打印關於鎖的附加信息,例如屬於java.util.concurrent的ownable synchronizers列表.
-m打印java和native c/c++框架的所有棧信息.
使用樣例:
[root@tts217 ~]# jstack -l 29984
.....
"main" prio=10 tid=0x00007fe648009000 nid=0x7521 runnable [0x00007fe64e753000]
java.lang.Thread.State: RUNNABLE
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
at java.net.ServerSocket.implAccept(ServerSocket.java:530)
at java.net.ServerSocket.accept(ServerSocket.java:498)
at org.apache.catalina.core.StandardServer.await(StandardServer.java:453)
at org.apache.catalina.startup.Catalina.await(Catalina.java:777)
at org.apache.catalina.startup.Catalina.start(Catalina.java:723)
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:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:321)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:455)
Locked ownable synchronizers:
- None
"VM Thread" prio=10 tid=0x00007fe64806a800 nid=0x7522 runnable
"VM Periodic Task Thread" prio=10 tid=0x00007fe6480a5800 nid=0x7529 waiting on condition
JNI global references: 238
二、JDK可視化工具
1、jconsole
JConsole是一個基於JMX的GUI工具,用於連接正在運行的JVM,不過此JVM需要使用可管理的模式啟動。如果要把一個應用以可管理的形式啟動,可以在啟動是設置com.sun.management.jmxremote。
jconsole可以選擇本地連接,來查看本地java程序參數,也可以連接遠程機器來使用,下面連接本地看:



b、內存:堆內存和其他內存。如下圖所示:

c、線程:峰值/活動線程,在此頁面可以查看到各個線程的明細,也可以進行死鎖檢測。如下圖所示:

d、類:監控加載和卸載的類,這個需要綜合其他工具進行具體的分析。

e、VM摘要:有關JVM的明細信息。

f、Mbean:當前Java程序的Mbean的操作。

在jconsole里主要可以用來監控內存和線程監控,內存監控相當於jstat,曲線可以選擇
可以手動執行gc。線程監控可用來檢測死鎖。

可以手動執行gc。線程監控可用來檢測死鎖。
死鎖代碼如下:
- package jvm;
- /**
- * 描述:
- *
- * @author alaric 2016年1月1日 上午12:43:23
- */
- public class A implements Runnable {
- int a, b;
- public A(int a, int b) {
- this.a = a;
- this.b = b;
- }
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- // 描述
- synchronized (Integer.valueOf(a)) {
- synchronized (Integer.valueOf(b)) {
- System.out.println(" a + b = " + (a + b));
- }
- }
- }
- public static void main(String[] args) {
- for (int i = 0; i < 100; i++) {
- new Thread(new A(1, 2)).start();
- new Thread(new A(2, 1)).start();
- }
- }
- }
多運行幾次會出現死鎖,程序會阻塞。然后用線程監控,點擊檢測死鎖,發現Thread-199和Thread-198相互等待釋放Integer.value(1)或者Integer.value(2)。因為在200次的代碼執行中Integer.value()就返回了兩個對象。

2、jvisualVM
jvisualVM所謂多合一虛擬機故障處理工具,有強大的插件擴展功能,通過安裝插件擴展支持,jvisualVM可以做到:
a、顯示虛擬機進程及進程的配置和環境信息(jps,jinfo);
b、監視應用程序CPU、GC、堆、方法區及線程的信息(jstat、jstack);
c、dump及分析堆轉儲快照(jmap、jhat);
d、方法級的程序性能分析,找出調用最多,運行時間最長的方法;
.....其它通過插件可以做到的;
概述里面可以看到虛擬機版本及配置的參數等。

在監視里可以看cpu、堆、線程類的相關數據。可以執行垃圾回收和dump堆。

在線程里可以看到所有線程,包括運行的、休眠的、等待的、駐留的等,包括運行時間。同時可以dump線程。
在抽樣器中可以監控到每個方法執行的時間,還可以對方法過濾。點擊線程cpu時間,可以看到每個線程cpu時間。
VisualGC這里可以看到虛擬機運行時每個區域的容量大小,已占用的大小,youngGC和fullGC的次數,以及編譯時間、類加載數量和加載時間等。

在抽樣器中可以監控到每個方法執行的時間,還可以對方法過濾。點擊線程cpu時間,可以看到每個線程cpu時間。

VisualGC這里可以看到虛擬機運行時每個區域的容量大小,已占用的大小,youngGC和fullGC的次數,以及編譯時間、類加載數量和加載時間等。

三、總結:
jdk提供的vm故障處理工具都比較實用,常用的jps,jstat,jmap,jstack以及可視化工具visualvm,當然根據個人實際實用情況,可能還選用第三方的工具進行dump分析,如eclipse的MAT(Memory Analyzer Tool)等。靈活實用這些工具,可以給處理問題帶來很大的便利。