前言
定位系統問題的時候,知識、經驗是基礎,資料是依據,工具是運用知識處理資料的手段。這裡說的資料包括:執行日誌、異常堆疊、GC日誌、執行緒快照、堆轉儲快照等。經常使用適當的虛擬機器監控和分析的工具可以加快分析資料、定位解決問題的速度。
jps:虛擬機器程式狀況工具
首先約定一下執行的程式碼都是以下這段
1 public class TestMain 2 { 3 public static void main(String[] args) 4 { 5 while (true) 6 { 7 8 } 9 } 10 }
JDK的很多小工具的名字都參考了UNIX命令的命名方式,jps(JVM Process Status)是其中的典型。除了名字像UNIX的ps命令外,它的功能也和ps命令類似:可以列出正在執行的虛擬機器程式,並顯示虛擬機器執行主類名稱以及這些程式的本地虛擬機器唯一ID(Local Virtual Machine Identifier,LVMID)。雖然功能比較單一,但它是使用最高的JDK命令列工具,因為其他的JDK工具大多需要輸入它查詢到的LVMID來確定要監控的是哪一個虛擬機器程式。
jps命令格式:
jps [ options ] [ hostid ]
jps工具主要選項
選 項 | 作 用 |
-q | 只輸出LVMID,省略主類的名稱 |
-m | 輸出虛擬機器程式啟動時傳遞給主類main()函式的引數 |
-l | 輸出主類的全名,如果程式執行的是jar包,輸出jar包路徑 |
-v | 輸出虛擬機器程式啟動時的JVM引數 |
jps執行樣例
某個虛擬機器程式執行TestMain這個類的main方法,看到10492就是該虛擬機器程式的ID
jstat:虛擬機器統計資訊監控工具
jstat(JVM Statistics Monitoring Tool)使用於監視虛擬機器各種執行狀態資訊的命令列工具。它可以顯示本地或者遠端(需要遠端主機提供RMI支援)虛擬機器程式中的類資訊、記憶體、垃圾收集、JIT編譯等執行資料,在沒有GUI,只提供了純文字控制檯環境的伺服器上,它將是執行期間定位虛擬機器效能問題的首選工具。
jstat命令格式
jstat [ option vmid [ interval [ s | ms ] [ count ] ] ]
這個VMID,對於本地虛擬機器程式而言,VMID和LVMID是一致的。引數interval和count分別表示查詢間隔和次數,如果省略這兩個引數,說明只查詢一次,假設需要每250毫秒查詢一次程式2764的垃圾收集情況,一共查詢20次,那命令應當是:
jstat -gc 2764 250 20
jstat主要工具選項
選 項 | 作 用 |
-class | 監視類裝載、解除安裝數量、總空間以及類裝載所耗費的時間 |
-gc | 監視Java堆狀況,包括Eden區、兩個Survivor區、、老年代、永久帶等的容量、已用空間、GC時間合計等資訊 |
-gccapacity | 監視內容基本與-gc相同,但輸出主要關注Java堆各個區域使用到的最大、最小空間 |
-gcutil | 監視內容基本與-gc相同,但輸出主要關注已使用的空間佔總空間的百分比 |
-gccause | 與-gcutil功能一樣,但是會額外輸出導致上一次GC產生的原因 |
-gcnew | 監視新生代GC狀況 |
-gcnewcapacity | 監視內容基本與-gcnew相同,但輸出主要關注使用到的最大、最小空間 |
-gcold | 監視老年代GC狀況 |
-gcoldcapacity | 監視內容基本與-gcold相同,但輸出主要關注使用到的最大、最小空間 |
-gcpermcapacity | 輸出永久代使用到的最大、最小空間 |
-compiler | 輸出JIT編譯器編譯過的方法、耗時等資訊 |
-printcompilation | 輸出已經被JIT編譯的方法 |
jstat執行樣例
jstat監視選項眾多,舉一個例子來檢視一下該命令如何檢視監視結果
查詢結果表明,新生代Eden區(E,表示Eden)使用了2%的空間,兩個Survivor區(S0、S1,表示Survivor0、Survivor1)都是空的,老年代(O,表示Old)和永久帶(P。表示Permanent)則分別使用了0%和13.84%的空間。程式執行以來共發生Minor GC(YGC,表示Young GC)0次,總共耗時0秒;發生Full GC(FGC,表示Full GC)3次,Full GC共耗時(FGCT,Full GC Time)為0秒,所有GC總耗時(GCT,表示GC Time)0秒。
jinfo:Java配置資訊工具
jinfo(Configuration Info for Java)的作用是實時地檢視和調整虛擬機器各項引數。使用jps命令的-v可以檢視虛擬機器啟動時顯式指定的引數列表,但如果想知道未被顯式指定的引數的系統預設值,可以使用jinfo的-flag選項進行查詢,jinfo還可以使用-sysprops選項把虛擬機器程式的System.getProperties()的內容列印出來。
jinfo命令格式
jinfo [ option ] pid
jinfo執行樣例
jinfo這個命令對於Windows平臺有較大限制,在Linux和Solaris系統才可以正常使用,所以這裡就不演示了。
jmap:Java記憶體映像工具
jmap(Memory Map for Java)命令用於生成堆轉儲快照。如果不使用jmap命令,要想獲取Java堆轉儲,可以使用“-XX:+HeapDumpOnOutOfMemoryError”引數,可以讓虛擬機器在OOM異常出現之後自動生成dump檔案,Linux命令下可以通過kill -3傳送程式退出訊號也能拿到dump檔案。
jmap的作用並不僅僅是為了獲取dump檔案,它還可以查詢finalize執行佇列、Java堆和永久代的詳細資訊,如空間使用率、當前使用的是哪種收集器等。和jinfo一樣,jmap有不少功能在Windows平臺下也是受限制的,除了生成dump檔案的-dump選項和用於檢視每個類的例項、空間佔用統計的-histo選項在所有作業系統都提供之外,其餘選項都只能在Linux和Solaris系統下使用。
jmap命令格式
jmap [ option ] vmid
jmap工具主要選項
選 項 |
作 用 |
-dump | 生成Java堆轉儲快照。格式為-dump:[live, ]format=b,file=<filename>,其中live自引數說明是否只dump出存活的物件 |
-finalizerinfo | 顯示在F-Queue中等待Finalizer執行緒執行finalize方法的物件。只在Linux和Solaris系統下有效 |
-heap | 顯示Java堆詳細資訊,如使用哪種收集器、引數配置、分代狀況等。只在Linux和Solaris系統下有效 |
-histo | 顯示堆中物件統計資訊,包括類、例項數量、合計容量 |
-permstat | 以ClassLoader為統計口徑顯示永久代記憶體狀態。只在Linux和Solaris系統下有效 |
-F | 當虛擬機器進行對-dump選項沒有響應時,可使用這個選項強制生成dump快照。只在Linux和Solaris系統下有效 |
jmap執行樣例
同樣,這個命令對Window環境限制也比較大,就不演示了。
jstack:Java堆疊跟蹤工具
jstack(Stack Trace for Java)命令用於生成虛擬機器當前時刻的執行緒快照。執行緒快照就是當前虛擬機器內每一條執行緒正在執行的方法堆疊的集合,生成執行緒快照的目的主要是定位執行緒長時間出現停頓的原因,如執行緒間死鎖、死迴圈、請求外部資源導致的長時間等待等都是導致執行緒長時間停頓的原因。執行緒出現停頓的時候通過jstack來檢視各個執行緒的呼叫堆疊,就可以知道沒有響應的執行緒到底在後臺做些什麼事情,或者在等待些什麼資源。
jstack命令格式
jstack [ option ] vmid
jstack主要工具選項
選 項 | 作 用 |
-F | 當正常輸出的請求不被響應時,強制輸出執行緒堆疊 |
-l | 除堆疊外,顯示關於鎖的附加資訊 |
-m | 如果呼叫到本地方法的時候,可以顯示C/C++的堆疊 |
jstack執行樣例
只擷取一部分,看到這就是10492這個虛擬機器程式ID當前時刻的執行緒快照。執行緒處於RUNNABLE狀態,執行到了TestMain函式的第7行,並且一直停留在第7行。
其他
上面都是利用命令採集指定程式的虛擬機器執行時的資訊,實際上,還可以利用視覺化工具對指定PID的虛擬機器執行時資訊進行監控,這裡推薦兩個:
1、JConsole
在Java_HOME/bin目錄下,有一個jconsole.exe,雙擊執行一下就可以了。
2、Visual VM
這個是到目前為止隨JDK釋出的功能最為強大的執行監視和故障處理工具,除了最基本的執行監視、 故障處理外,還有效能分析的功能,且十分強大。Visual VM還有一個很大的優點,它對應用程式的實際效能影響很小,使得它可以直接應用在生產環境中。
至於具體如何使用,就不演示了,比較簡單。除了上面兩個工具,還可以使用JProfiler、YourKit等專業且收費的Profiling工具。