前言
給一個系統定位問題的時候,知識、經驗是關鍵基礎,數據是依據,工具是運用知識處理數據的手段。
這裏的數據包括:
- 運行日誌
- 異常堆棧
- GC日誌
- 線程快照(threaddump/javacore)
- 堆轉儲快照(headdump/hprof文件)等
JDK中自帶的命令,能在處理應用程序性能問題、定位故障時發揮很大的作用。
生產環境,無論是直接接觸物理服務器,還是遠程Telnet到服務器上都可能會受到限制,藉助tools.jar類庫裏面的接口,也就是我們剛說的JDK中自帶的工具,可以直接在應用程序中實現功能強大的監控分析功能。
一、 jps: 虛擬機進程狀況工具
在瞭解這個命令前,我們現需要了解進程與線程的概念,進程是更大的概念,是一個獨立運行的程序,而線程是更小的概念,一個進程中可以有多個線程。
jps就是專門用來查看系統中有哪些進程的工具,以便根據查詢出來的進程ID,也就是後文中我們說的vmid,來使用後面的JDK中的其他命令。
jps可以有以下參數:
選項 | 作用 |
---|---|
-q | 只輸出進程ID,省略主類的名稱 |
-m | 輸出進程啓動時傳遞給主類main( )函數的參數 |
-l | 輸出主類的全名,如果進程執行的是Jar包,輸出Jar路徑 |
-v | 輸出虛擬機進程啓動時JVM參數 |
jps -l,jps -v這兩個命令用的最多。
二、jstat: 虛擬機統計信息監視工具
jstat用於監視虛擬機各種運行狀態信息的命令行工具。
它可以顯示本地或者遠程虛擬機進程中:
- 類裝載
- 內存
- 垃圾收集
- JIT編譯等運行數據。
在沒有GUI圖形界面,只提供了純文本控制檯環境的服務器上,它將是運行期定位虛擬機性能問題的首選工具。
jstat命令的格式爲:
jstat option vmid [interval][s|ms] [count]
如果是遠程虛擬機進程,那麼vmid的格式爲:
[protocol:][//]vmid[@hostname[:port]/servername]
jstat中的參數interval和count代表查詢的間隔和次數,如果省略這兩個參數,說明只查詢一次。假設我們每秒查詢一次進程id爲3001的垃圾收集情況,一共查詢20次。
jstat -gc 3001 1000 20
jstat中的option代表着用戶希望查詢的虛擬機信息,主要分爲三類:類裝載、垃圾收集、運行期編譯情況,具體參數如下表:
選項 | 作用 |
---|---|
-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工具在純文本狀態下監視虛擬機狀態的變化,確實不如後面提到的VisualVM等可視化的監視工具直接以圖表展現那樣直觀。
但許多服務器管理員都習慣了在文本控制檯中工作,直接在控制檯中使用jstat命令依然是一種常用的監控方式。
三、 jinfo: Java配置信息工具
jinfo的作用是實時的查看和調整虛擬機各項參數。
使用jps命令的-v參數可以查看虛擬機啓動時顯式指定的參數列表。但如果想知道未被顯式指定的參數的系統默認值,除了找資料外,就只能使用jinfo的**-flag選項進行查詢了**。
另外直接使用以下命令,可以打印所有參數默認值。
java -XX:+PrintFlagsFinal
jinfo還可以使用**-sysprops**選項把虛擬機進程的System.getProperties( )的內容打印出來。
jinfo可以使用**-flag [+|-] name** 來設置布爾值的變量,+是true,-是false。
jinfo -flag +PrintGC vmid
jinfo -flag +PrintGCDetails vmid
jinfo -flag +PrintGCTimeStamps vmid
jinfo -flag +PrintGCDateStamps vmid
jinfo使用 -flag name=value 修改一部分運行期可寫的虛擬機參數值。
比如查詢CMSInitiatingOccupancyFraction參數值:
jinfo -flag CMSInitiatingOccupancyFraction vmid
四、jmap: Java內存映像工具
讓虛擬機生成dump文件的方式有以下多種:
- jmap命令用於生成堆轉儲快照。
- 當然我們可以通過虛擬機參數**-XX:HeapDumpOutOfMemory**,使虛擬機在出現異常時打印dump文件。
- 或者通過**-XX:+HeapDumpOnCtrlBreak**參數,可以通過Ctrl+Break鍵讓虛擬機生成dump文件。
- 或者在Linux系統下通過kill -3命令發送進程退出信號,嚇唬一下虛擬機,也能拿到dump文件。
jmap不僅僅是爲了獲取dump文件,它還可以查詢finalize執行隊列、Java堆和永久代的詳細信息,如空間使用率、當前用的是哪種收集器等。
jmap命令格式如下:
jmap [option] vmid
option選項的合法值與具體含義如下:
選項 | 作用 |
---|---|
-dump | 生成Java堆轉儲快照,格式爲-dump:[live,]format=b,file=,其中live子參數說明是否只dump出存活的對象 |
-finalizerinfo | 顯示在F-Queue中等待Finalizer線程執行finalize方法的對象。 |
-heap | 顯示Java堆詳細信息,如使用哪種回收器、參數配置、分代狀況等。 |
-histo | 顯示堆中對象統計信息,包括類、實例數量、合計容量 |
-F | 當虛擬機進程對-dump選項沒有響應時,可使用這個選項強制生成dump快照。 |
jmap生成dump文件的一個例子:
jmap -dump:format=b,file=demo.bin 12639
五、jhat: 虛擬機堆轉儲快照分析工具
jhat命令與jmap搭配使用,來分析jmap生成的堆轉儲快照。jhat內置了一個微型的http/htmp服務器,來生成dump文件的分析結果後,可以在瀏覽器中查看。
當然除非沒有別的工具可以使用,否則我們很少使用jhat工具,因爲分析工作是一個耗時而且消耗硬件資源的過程。另外jhat工具相對比較簡陋,沒有其他的工具好用。
命令爲:
jhat demo.bin
當日志打印”Server is ready“,我們可以在瀏覽器當中輸入http://localhost:7000/就可以看到分析結果了。
分析結果默認是以包爲單位進行分組顯示,分析內存泄漏問題主要會使用其中的:
-
Heap Histogram:可以找到內存中總容量最大的對象。
-
OQL頁籤的功能:是標準的對象查詢語言。
六、jstack: Java堆棧跟蹤工具
jstack命令用於生成虛擬機當前時刻的線程快照,一般稱爲threaddump或Javacore文件。
線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現長時間停頓的原因:
- 線程間死鎖
- 死循環
- 請求外部資源導致的長時間等待都是導致線程長時間停頓的常見原因
使用jstack來查看各個線程的調用堆棧,就可以知道沒有響應的線程到底在後臺做些什麼事情,或者等待着什麼資源。
jstack的命令格式如下:
jstack [option] vmid
其中的option選項意義如下:
選項 | 作用 |
---|---|
-F | 當正常的輸出的請求不被響應時,強制輸出線程快照 |
-l | 除堆棧外,顯示關於鎖的附加信息 |
-m | 如果調用到本地方法的話,可以顯示C/C++的堆棧 |
在JDK1.5以後,java.lang.Thread類新增了一個**getAllStackTraces( )**方法,用於獲取虛擬機中所有線程的StackTraceElement對象,在實際的項目中,可以通過調用這個方法做個管理員頁面,可以隨時使用瀏覽器來查看線程堆棧。
總結
JDK中自帶工具的功能總結如下:
名稱 | 主要作用 |
---|---|
jps | 顯示指定系統內所有的虛擬機進程 |
jstat | 用於收集虛擬機各方面的運行數據 |
jinfo | 顯示虛擬機配置信息 |
jmap | 生成虛擬機的內存轉儲快照 |
jhat | 用於分析heapdump文件,它會建立一個http/html服務器,讓用戶可以在瀏覽器上查看分析結果 |
jstack | 顯示虛擬機的線程快照 |