第四章 虛擬機性能監控與故障處理工具
4.1 概述
經常使用適當的虛擬機監控和分析工具可以加快我們分析數據、定位解決問題的速度。這裏所說的數據包括:運行日誌、異常堆棧、GC 日誌、線程快照(threaddump / javacore 文件)、堆轉儲快照(headdump / hprof 文件)等
4.2 JDK 的命令行工具
Sun 公司(現在應該是 Oracle 了)其實爲Java開發者提供了許多的免費便利工具,雖然他們在軟件的使用說明上把他們聲明爲“沒有技術支持並且是實驗性質的(unsupported and experimental)的產品”,但事實上這些工具都非常的穩定且強大。如圖:
大家能看到其實大部分的工具類都穩定在16-17KB左右,這其實是因爲這些工具類只不過是在 tools.jar 類庫的一層薄包裝而已。不信我們看下 tools.jar 裏都有啥:
怎麼樣,有沒有看到我們熟悉的東西。jps jstat jmap jstack~
至於Linux上的JDK,實際上是一樣的:
介紹幾個常用的:
名稱 | 主要作用 |
---|---|
jps | JVM Process Status Tool,顯示指定系統內所有HotSpot虛擬機進程 |
jstat | JVM Statistics Monitoring Tool,用於收集HotSpot虛擬機各方面的運行數據 |
jinfo | Configuration Info for Java,顯示虛擬機配置信息 |
jmap | Memory Map for Java,生成虛擬機的內存轉儲快照(heapdump文件) |
jhat | JVM Heap Dump Browser,用於分析 heapdump 文件,他會建立一個 HTTP/HTML 服務器,讓用戶可以在瀏覽器上查看分析結果 |
jstack | Stack Trace for Java,顯示虛擬機的線程快照(threaddump) |
爲做以下實驗,寫了個簡單的小程序來模擬正常程序運行:
public class JVMTools {
public JVMTools() {
System.out.println(System.currentTimeMillis() + " A New Object (" + this.toString() + ") Created!");
}
public static final int _1MB = 1024 * 1024;
// 老規矩,創建一個佔點內存的對象,好觀測
private byte[] arr = new byte[2 * _1MB];
private int a = 0;
public void add() throws InterruptedException {
for (int i = 0; i < 100; i++) {
a ++;
Thread.sleep(100);
}
System.out.println(System.currentTimeMillis() + " Object (" + this.toString() + ") execute add method end!");
}
public static void main(String[] args) throws InterruptedException {
while (true) {
new Thread(() -> {
JVMTools tmp = new JVMTools();
try {
// 保證他能存活10秒鐘
tmp.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(1000);
}
}
}
大體意思就是每秒創建一個對象,對象的存活時間爲10秒,也就是說理論上內存中總有10個存活對象,用來觀察內存的變化。
4.2.1 jps:虛擬機進程狀況工具
jps 的作用就是列出當前在運行的 JVM,查出的 LVMID 跟操作系統中的 PID (進程ID)是一致的,
jps 的命令格式如下:
jps [options] [hostid] 例如 jps -l
jps 可以通過 RMI協議查詢開啓了 RMI 服務器的遠程虛擬機進程狀態,命令中的 hostid 爲 RMI 註冊表中註冊的主機名。jps其他常用選項看下錶:
選項 | 作用 |
---|---|
-q | 只輸出 LVMID ,省略主類的名稱 |
-m | 輸出虛擬機進程啓動時傳遞給主類 main() 函數的參數 |
-l | 輸出主類的全名,如果進城執行的是 Jar 包,則輸出包路徑 |
-v | 輸出虛擬機進程啓動時的 JVM 參數 |
例如:
4.2.2 jstat:虛擬機統計信息監視工具
jstat(JVM Statistics Monitoring Tool)是用於監視虛擬機各種運行狀態信息的命令行工具。它可以顯示本地或者遠程虛擬機進程中的類裝載、內存、垃圾收集、JIT 編譯等運行數據,在沒有 GUI 圖形界面,只提供純文本控制檯環境的服務器上,它將是運行期定位虛擬機性能問題的首選工具。
jstat 命令格式爲:
jstat [ option vmid [ interval [ s | ms ] [count] ] ] 例如 jstat -gcutil 20028 100 25
具體選項如下:
選項 | 作用 |
---|---|
-class | 監視類裝載、卸載數量、總空間及類裝載所耗費的時間 |
-gc | 監視Java堆狀況,包括 Eden 區、2個 survivor 區、老年代、永久代等的容量,已用空間、 GC 時間合計等信息 |
-gccapacity | 監視內容與 -gc 基本相同,但輸出主要關注 Java 堆各個區域使用到的最大和最小空間 |
-gcuil | 監視內容與 -gc 基本相同,但輸出主要關注已使用空間佔總空間的百分比 |
-gccause | 與 -gcutil 功能一樣,但是會額外輸出導致上一次 GC 產生的原因 |
-gcnew | 監視新生代 GC 的狀況 |
-gcnewcapacity | 監視內容與 -gcnew 基本相同,輸出主要關注使用到的最大和最小空間 |
-gcold | 監視老年代 GC 的狀況 |
-gcoldcapacity | 監視內容與 -gcold 基本相同,輸出主要關注使用到的最大和最小空間 |
-compiler | 輸出JIT編譯器編譯過的方法,耗時等信息 |
-printcompilation | 輸出已經被JIT編譯的方法 |
這些選項太多,不一一實驗,僅以最簡單的爲例:
這截圖代表的意思是 針對 20028 每100 毫秒 記錄一次,共記錄 25 次GC信息,
字段含義如下:
- S0:第一個倖存區的使用比例
- S1:第二個倖存區的使用比例
- E:Eden 區的使用比例
- O:Old 區的使用比例
- M:方法區的使用比例
- CCS:壓縮區的使用比例
- YGC:年輕代垃圾回收次數
- YGCT:年輕代垃圾回收消耗時間
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
其餘字段都好理解,這個CCS可能會難懂一些,不過當你仔細研讀了 JDK8 中的Meta Space 後就知道了。這邊我簡單講下,參考博客如下:
- https://www.cnblogs.com/duanxz/p/3520829.html
- http://lovestblog.cn/blog/2016/10/29/metaspace/
CCS 全名爲 Compressed Class Pointer Space(類指針壓縮空間),它實際上是 JDK 8 中元數據區的一部分。前兩天的博客中有提到過方法區原來存在永久代中,後來放到了元空間,每個對象實例中都有一個指針指向自己的類信息,也就是我們說的 klass ,那麼這個指針就是 _klass 指針,那這個指針在不同的虛擬機中所佔的長度也不同。例如 32 位虛擬機中,_klass 指針佔 4 字節,但是 64 位虛擬機中 _klass 指針就佔了 8 字節。爲了壓縮對象中的 _klass 指針的大小,引入了 CCS 這麼個區域,就是說只有是64位平臺上啓用了類指針壓縮纔會存在這個區域。CCS 中只包含類的元數據,剩下的信息還是放在 Meta Space 中。這裏這個CCS 字段,實際上指的是 CCS 的已使用率,具體算法是 :
(1-((sun.gc.compressedclassspace.capacity - sun.gc.compressedclassspace.used)/sun.gc.compressedclassspace.capacity)) * 100
capacity 代表的是 CCS 的總容量(在內存中已經 Commit的)大小,used 則代表已經使用的。
在截圖中我們可以明顯的看到因爲新對象的創建導致的 Eden 區使用率上漲。
4.2.3 jinfo:Java 配置信息工具
jinfo 可以用來查看正在運行的 JVM 的各項參數,它還可以通過 -sysprops 參數打印出虛擬機進程的 System.getProperties() 的內容。它也可以通過 -flag [ +|- ] name 或 -flag name=value 兩種方式動態的修改正在運行的 JVM 一些參數。當系統崩潰時,jinfo可以從core文件裏面知道崩潰的Java應用程序的配置信息。實例如下:
jinfo -sysprops 20028
jinfo -flags 20028 :
4.2.4 jmap: Java 內存映像工具
jmap 就是我們常常用來做 heapdump 的主要工具,雖然可以用其他方式(例如 加一些 JVM 啓動參數)來生成,但是 jmap 仍然是最方便的一種。話不多說上用法(不弄表格了,懶了懶了):
Usage:
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
where <option> is one of:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
不做表格詳細說明了,用爛了都。話不多說上例子:
jmap -dump:live,format=b,file=Demo.hprof 20028
4.2.5 jhat:虛擬機轉儲快照分析工具
JDK 自身提供一種分析dump文件的工具—— jhat(JVM Heap Analysis Tool)命令與 jmap 搭配使用。但是實話說一般人都不用,太難用了。都不如 VisualVM,用的最多的應該還要數 Eclipse Memory Analyzer 和 IBM HeapAnalyzer 兩大工具了。不管怎樣,寫都寫了,就展示一下吧:
待出現Server is ready字樣,輸入http://localhost:7000/ 即可查看
4.2.6 jstack: Java 堆棧跟蹤工具
jstack(Stack Track for Java)命令,可以生成當前虛擬機當前時刻的線程快照(threaddump/Javacore)。用以分析是否發生死鎖,線程爲何反應時間過長等問題。可以看到詳細的java棧信息,老規矩不上表格了:
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message
同樣是用爛了的命令,話不多說上例子:
# 直接查看棧信息
jstack -l 20028
# 將棧信息保存在 threaddump.log 文件中
jstack -l 20028 >> threaddump.log
這裏還能把文件保存下來,爲什麼要保存呢。因爲有這個好東西:
https://www.fastthread.io/
這個網站可以分析你上傳的dump文件,幫助快速定位。示例如下:
多餘的圖就不放了,大家感興趣的自行探索~
4.3 JDK 的可視化工具
JDK 中實際上提供了兩種可視化工具,而這兩種工具並未被貼上 unsupported and experimental 的標籤,那就是 Jconsole 和 VisualVM 。
4.3.1 JConsole:Java 監視與管理控制檯
啓動
通過目錄下的jconsole.exe 啓動後,可以直接選擇線程而無需使用 jps 再去查
連接上之後,就可以很直觀的看到概覽、內存、線程、類等趨勢圖:
書中針對工具有不同的例子作解釋,此處不再展開說。有興趣的童鞋可以參考原書自行研究~
4.3.2 VisualVM:多合一處理故障工具
VisualVM 無法直接啓動,是需要通過插件啓動的。比如我使用的 IntelliJIDEA2019.2.3 。啓動的時候帶有插件:
程序啓動後會隨之將 VisualVM 一併啓動。VisualVM 啓動後會出現如下圖所示概覽,書中對軟件使用方法做了詳細描述,本文不再贅述,僅挑部分功能截圖。
- 概覽:
- GC 歷史可視化
- 快速dump
- 快速dump做下來的 heapdump
- 快速dump做下來的 threaddump
本章主要是講解一些隨JDK的實用小工具,用時再回來翻閱即可
本文僅是在自我學習 《深入理解Java虛擬機》這本書後進行的自我總結,有錯歡迎友善指正。
歡迎友善交流,不喜勿噴~
Hope can help~