深入理解Java虛擬機-第四章 虛擬機性能監控與故障處理工具

第四章 虛擬機性能監控與故障處理工具

4.1 概述

經常使用適當的虛擬機監控和分析工具可以加快我們分析數據、定位解決問題的速度。這裏所說的數據包括:運行日誌、異常堆棧、GC 日誌、線程快照(threaddump / javacore 文件)、堆轉儲快照(headdump / hprof 文件)等

4.2 JDK 的命令行工具

Sun 公司(現在應該是 Oracle 了)其實爲Java開發者提供了許多的免費便利工具,雖然他們在軟件的使用說明上把他們聲明爲“沒有技術支持並且是實驗性質的(unsupported and experimental)的產品”,但事實上這些工具都非常的穩定且強大。如圖:
jdk 中的工具
大家能看到其實大部分的工具類都穩定在16-17KB左右,這其實是因爲這些工具類只不過是在 tools.jar 類庫的一層薄包裝而已。不信我們看下 tools.jar 裏都有啥:tools.jar
怎麼樣,有沒有看到我們熟悉的東西。jps jstat jmap jstack~
至於Linux上的JDK,實際上是一樣的:
Linux 版本JDK bin目錄
介紹幾個常用的:

名稱 主要作用
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 列出的線程
操作系統的 PID
jps 的命令格式如下:
jps [options] [hostid] 例如 jps -l
jps 可以通過 RMI協議查詢開啓了 RMI 服務器的遠程虛擬機進程狀態,命令中的 hostid 爲 RMI 註冊表中註冊的主機名。jps其他常用選項看下錶:

選項 作用
-q 只輸出 LVMID ,省略主類的名稱
-m 輸出虛擬機進程啓動時傳遞給主類 main() 函數的參數
-l 輸出主類的全名,如果進城執行的是 Jar 包,則輸出包路徑
-v 輸出虛擬機進程啓動時的 JVM 參數

例如:
jps -v
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編譯的方法

這些選項太多,不一一實驗,僅以最簡單的爲例:
jstat -gcutil 20028 100 25
這截圖代表的意思是 針對 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 -sysprops 20028
jinfo -flags 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

創建dump
新鮮的dump文件

4.2.5 jhat:虛擬機轉儲快照分析工具

JDK 自身提供一種分析dump文件的工具—— jhat(JVM Heap Analysis Tool)命令與 jmap 搭配使用。但是實話說一般人都不用,太難用了。都不如 VisualVM,用的最多的應該還要數 Eclipse Memory Analyzer 和 IBM HeapAnalyzer 兩大工具了。不管怎樣,寫都寫了,就展示一下吧:

jhat Demo.hprof
待出現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

jstack -l 20028
這裏還能把文件保存下來,爲什麼要保存呢。因爲有這個好東西:
https://www.fastthread.io/
這個網站可以分析你上傳的dump文件,幫助快速定位。示例如下:
總覽
Bottom up Call Stack Tree
多餘的圖就不放了,大家感興趣的自行探索~

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 歷史可視化
    GC 圖形
  • 快速dump
    快速dump
  • 快速dump做下來的 heapdump
    heapdump
  • 快速dump做下來的 threaddump
    threaddump

本章主要是講解一些隨JDK的實用小工具,用時再回來翻閱即可

本文僅是在自我學習 《深入理解Java虛擬機》這本書後進行的自我總結,有錯歡迎友善指正。

歡迎友善交流,不喜勿噴~
Hope can help~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章