1.JDK命令行工具
Java開發人員肯定都知道JDK的bin目錄有“java.exe”,"javac.exe"這兩個命令行工具,但並非所有程序員都了解過JDK的bin目錄之中其他命令行程序的作用。每次JDK更新,bin目錄下命令行工具的數量和功能總會不知不覺地增強。
主要包括用於監控虛擬機和故障處理的工具。這些工具被Sun公司作為禮物附贈給JDK的使用者。如下圖:

可以看到這些工具的程序體積都異常小巧。基本都穩定在17K左右。這並非JDK開發團隊刻意把他們制作得如此精煉,而是這些命令行工具大多數是JDK/lib/tools.jar類庫的一層薄包裝而已,它們主要的功能代碼是在tools類庫中實現的。
之所以這樣做,是因為當應用程序部署到生產環境后,無論是直接接觸物理服務器還是遠程Telnet到服務器上都可能會受到限制。借助tools.jar類庫里面的接口,我們可以直接在應用程序中實現功能強大的監控分析功能。
下面列舉JDK主要命令行監控工具的用途。


1.jps:虛擬機就進程狀況工具
JDK的很多小工具的名字都參考了UNIX命令的命名方式,jps名字像UNIX的ps命令之外,也和ps命令類似:可以列出正在運行的虛擬機進程。並顯示虛擬機執行主類(Main Class,main()函數所在的類)名稱以及這些進程的本地虛擬機唯一ID(Local Virtual Machine Identifier,LVMID)。
雖然功能比較單一,但它是使用頻率最高的JDK命令行工具,因為其他的JDK工具大多需要輸入它查詢到的LVMID來確定要監控的是哪一個虛擬機進程。對於本地虛擬機進程來說,LVMID與操作系統的進程ID是一致的。使用Windows的任務管理器或者UNIX的ps命令也可以
查詢到虛擬機進程的LVMID,但如果同時啟動多個虛擬機進程,無法根據進程名稱定位時,那只有依賴jps命令顯示主類的功能才能區分了。
jps命令格式如下:

現在我們打開一個eclispe,寫一段程序,例子如下:
package hjc.test9a; import java.util.Scanner; /** * Created by cong on 2018/4/5. */ public class Main { public Main() { } public static void main(String[] args) { Scanner sc = new Scanner(System.in); sc.next(); } }
連續運行2次,打開cmd,再用jps查看,如下:

2.jstat:虛擬機統計信息監控工具
jstat(JVM Statistics Monitoring Tool)是用於監控虛擬機各種運行狀態信息的命令行工具。它可以顯示本地或者遠程虛擬機進程中的類裝載,內存,垃圾收集,JIT編譯等運行數據,在沒有GUI圖形界面,只提供了純文本控制台環境的服務器上,
它將是運行期定位虛擬機性能問題的首選工具。
jstat命令格式為:
jstat [ option vmid [interval [s|ms] [count]] ]
對於命令格式中的VMID與LVMID需要特別說明一下:如果是本地虛擬機進程,VMID與LVMID是一致的,如果是遠程虛擬機進程,那VMID的格式應當是:

參數interval 和count代表查詢間隔和次數,如果省略這兩個參數,說明只查詢一次。假設要美250毫秒查詢一次進程2764垃圾收集情況,一個查詢20次,那命令應當是:
jstat -gc 2764 250 20
選項option代表着用戶希望查詢的虛擬機信息,主要分為3類:類裝載,垃圾收集,運行期編譯狀況,具體選項及作用請參考如下列表:

jstat 監控選項眾多,這里僅舉一個例子演示如何查看監控結果。繼續運行上面的例子如下:

3.jinfo:Java配置信息工具
jinfo(Configuration Info for Java) 的作用是實時地查看和調整虛擬機各項參數。使用jps命令的-v參數可以查看虛擬機啟動時顯式指定的參數列表,但如果想知道未被顯式指定的參數的系統默認值,除了去找資料,就只能使用jinfo的-flag選項進行查詢了(如果
只限於JDK1.6或以上版本的話,使用java -XX:+PrintFlagsFianl查看參數默認值也是一個很好的選擇),jinfo還可以使用-sysprops選項把虛擬機進程的System.getProperties()的內容打印出來。這個命令在JDK1.5時期已經伴隨Linux的JDK發布,當時只提供了信息查詢的功能,
JDK1.6之后,jinfo在Windows和Linux平台都有提供,並且加入了運行期修改參數的能力,可以使用-flag [+|-] name或者 -flag name=value 修改一部分運行期可寫的虛擬機參數值。JDK1.6中,jinfo對於Windows平台功能仍然有很大的限制,只提供了最基本的-flag選項。
jinfo的命令格式如下:
jinfo [option] pid

jmap:Java內存映像工具
jmap命令用於生成堆轉儲快照(一般稱為heapdump 或者dump文件),如果不是用jmap命令,想要獲取Java堆轉儲快照,要有一些暴力手段,用-XX:HeapDumpOnOutOfMemoryError參數,可以讓虛擬機在OOM異常出現之后自動生成dump文件,通過-XX:HeapDumpOnCtrlBreak參數則
可以使用[Ctrl]+[Break]鍵讓虛擬機生成dump文件,又或者在Linux系統下通過Kill -3命令發送進程退出信號嚇唬一下虛擬機,也能拿到dump文件。jmap的作用並不僅僅是為了獲取dump文件,它還可以查詢finalize執行隊列,java堆和永久代的詳細信息,如空間使用率,當前用的是哪種收集器等。
jmap有不少功能在Windows平台下都是受限制的,除了生成dump文件的-dump選項和用於查看每個類的實例,空間占用統計的-histo選項在所有操作系統都提供外,其余只能在Linux/Solaris下使用。
jmap命令格式:
jmap [option] vmid
option選項合法值與具體含義如下:

例子如下:



5.jhat:虛擬機堆轉儲快照分析工具
jhat命令與jmap搭配使用,來分析jmap生成的堆轉儲快照。jhat內置了一個微型的HTTP/HTML服務器,生成dump文件的分析結果后,可以在瀏覽器查看。實際工作中,如果沒有別的工具可用,一般不會用jhat分析dump文件的。
原因有二:一是一般不會在部署應用程序的服務器上直接分析dump文件,即使這樣做,也會盡量將dump文件復制到其他機器上進行分析,因為分析工作是一個耗時並且消耗硬件資源的過程。另外一個原因是jhat的分析功能相對於簡陋,
后面會提到專業的工具VisualVM,以及專業分析dump的Eclispe Memory Analyzer,等工具。



6.jstack:Java堆棧跟蹤工具
jstack命令用於生成虛擬機當前時刻的線程快照(一般稱為threaddump或者javacore文件)。線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧集合,生成線程快照的主要目的是定位線程出現長時間停頓的原因。線程出現停頓的時候通過
jstack來查看各個線程的調用堆棧,就可以知道沒有響應的線程到底在后台做些什么事情,或者等待着什么資源
jstack命令格式如下:
jstack [option] vmid
option選項的合法值與具體含義如下:

例子如下:

在JDK1.5中,java.lang.Thread類新增了一個getAllStackTraces()方法用於獲取虛擬機中所有線程的StackTraceElement對象。使用這個方法可以通過簡單的幾行代碼就完成了jstack的大部分功能。在實際項目中不妨調用這個方法做個管理員頁面,可以隨時使用瀏覽器
來查看線程堆棧,例子如下:
package hjc.test9b; import java.util.Map; /** * Created by cong on 2018/4/5. */ public class Main { public static void main(String[] args) { Map<Thread, StackTraceElement[]> m = Thread.getAllStackTraces(); for (Map.Entry<Thread, StackTraceElement[]> en : m.entrySet()){ Thread t = en.getKey(); StackTraceElement[] v = en.getValue(); System.out.println("The Thread name is :" + t.getName()); for (StackTraceElement s : v){ System.err.println("\t" + s.toString()); } } } }
運行結果如下:

7.JConsole:Java監控與管理控制平台。
JConsole是一種基於JMX的可視化監視,管理工具。通過JDK/bin目錄下的jconsole.exe來啟動JConsole

雙機她進去,可以看到主界面包括概述,內存,線程,類,VM摘要,MBean6個頁面

對線程的監控例子如下:







死鎖代碼樣例:


這段代碼開了200個線程去分別計算1+2以及2+1的值,造成死鎖的原因是Integer.valueOf()方法基於減少對象創建次數和節省內存的考慮,[-128,127]之間的數字會被緩存,當valueOf()方法傳入參數在這個范圍之內,將直接返回緩存中的對象。也就是說
代碼中調用200次Integer.valueOf()方法一共就返回了兩個不同的對象。假如在某個線程的兩個synchronized塊之間發生了一次線程切換,那就會出現線程A等線程B持有的Integer.valueOf(1),線程B又等待着被線程A持有的Integer.valueOf(2),結果大家都跑不下去。
出現思索后,點擊Jconsole線程面板的檢測到死鎖的按鈕,將出現一個新的死鎖標簽。如下圖:

8.VisualVM:多合一故障處理工具
VisualVM可以做到:
1.顯示虛擬機繼承以及進程的配置,環境信息(jps,jinfo)
2.監視應用程序的CPU,GC,堆,方法區,以及縣城信息(jstack,jstat)
3.dump以及分析堆轉快照(jmap,jhat)
4.方法級的程序運行性能分析,找出被調用最多,運行時間最長的方法。
5.離線程序快照:收集程序的運行時配置,線程dump,內存dump等信息建立一個快照,可以將快照發送開發者進行BUG反饋。

安裝后,打開如下:

