虛擬機的監控工具


定位問題,知識儲備是基礎,日志等數據是依據,工具則是幫助我們事半功倍的手段。

 

本文是在win下測試,主要介紹一些工具的使用。

 

1.jps:虛擬機進程狀況工具

JVM Process Status Tool

可以列出正在運行的虛擬機進程,並顯示虛擬機執行主類(Main Class,main()函數所在的類)名稱以及這些進程的本地虛擬機唯一ID(LVMID,Local Virtual Machine Identifier)。

C:\Users\***\Desktop\64124-深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)_源碼>jps -l
39172 sun.tools.jps.Jps
24396
24476 org.jetbrains.jps.cmdline.Launcher

 

 

 

 

2.jstat:虛擬機統計信息工具

JVM Statistics Monitoring Tool

jstat(JVM Statistics Monitoring Tool)是用於監視虛擬機各種運行狀態信息的命令行工具。它可以顯示本地或者遠程[插圖]虛擬機進程中的類加載、內存、垃圾收集、即時編譯等運行時數據,在沒有GUI圖形界面、只提供了純文本控制台環境的服務器上,它將是運行期定位虛擬機性能問題的常用工具。

C:\Users\***\Desktop\64124-深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)_源碼>jstat -gcutil 24476
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
 75.50   0.00  76.86   0.20  97.04  92.93      2    0.009     0    0.000    0.009

查詢結果表明:這台服務器的新生代Eden區(E,表示Eden)使用了76.8%的空間,2個Survivor區(S0、S1,表示Survivor0、Survivor1),老年代(O,表示Old)和永久代(P,表示Permanent)則分別使用了0.2%和97.4%的空間(這里沒有P只有M,對照看的話應該就是P)。程序運行以來共發生MinorGC(YGC,表示Young GC)2次,總耗時0.1009秒;發生Full GC(FGC,表示Full GC)0次,總耗時(FGCT,表示Full GC Time)為0秒;所有GC總耗時(GCT,表示GC Time)為0.009秒。

 

 

 

3.jinfo:Java配置信息

configuration info for java

這里也就是查-XX:....這類的配置

C:\Users\***\Desktop\64124-深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)_源碼>jinfo -flag CMSInitiatingOccupancyFraction 24476
-XX:CMSInitiatingOccupancyFraction=-1

 

4.jmap:java內存映像工具

memory map for java

 

jmap(Memory Map for Java)命令用於生成堆轉儲快照(一般稱為heapdump或dump文件)。如果不使用jmap命令,要想獲取Java堆轉儲快照也還有一些比較“暴力”的手段:譬如在第2章中用過的-XX:+HeapDumpOnOutOfMemoryError參數,可以讓虛擬機在內存溢出異常出現之后自動生成堆轉儲快照文件,通過-XX:+HeapDumpOnCtrlBreak參數則可以使用[Ctrl]+[Break]鍵讓虛擬機生成堆轉儲快照文件,又或者在Linux系統下通過Kill-3命令發送進程退出信號“恐嚇”一下虛擬機,也能順利拿到堆轉儲快照。對於IDEA的話還有快捷鍵。

C:\Users\***\Desktop\64124-深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)_源碼>jmap -dump:format=b,file=eclipse.bin 24476
Dumping heap to C:\Users\hufan\Desktop\64124-深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)_源碼\eclipse.bin ...
Heap dump file created

 

 

 

5.jhat:堆轉儲快照分析

jvm heap analysis tool

主要是分析jmap的堆快照,基本沒人用

 

C:\Users\***\Desktop\64124-深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)_源碼>jhat eclipse.bin
Reading from eclipse.bin...
Dump file created Mon Feb 03 13:25:03 CST 2020
Snapshot read, resolving...
Resolving 3026440 objects...
Chasing references, expect 605 dots............................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
....
Eliminating duplicate references...............................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
...............................................................................................................................................................
.
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

這時打開瀏覽器輸入   http://localhost:7000/  可以看分析結果了。

 

6.jsatck:java堆棧跟蹤工具

stack trace for java

這個主要是查看各個線程堆棧

C:\Users\***\Desktop\64124-深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)_源碼>jstack 24396
2020-02-03 13:29:05
Full thread dump OpenJDK 64-Bit Server VM (25.202-b44 mixed mode):

"JobScheduler FJ pool 4/7" #170 daemon prio=4 os_prio=-1 tid=0x00000000242dd000 nid=0x2d6c waiting on condition [0x000000004662f000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000e33ce9b0> (a java.util.concurrent.ForkJoinPool)
        at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

"JobScheduler FJ pool 3/7" #169 daemon prio=4 os_prio=-1 tid=0x00000000242dc800 nid=0x9770 waiting on condition [0x000000004652f000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000e33ce9b0> (a java.util.concurrent.ForkJoinPool)
        at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

 

從JDK 5起,java.lang.Thread類新增了一個getAllStackTraces()方法用於獲取虛擬機中所有線程的StackTraceElement對象。使用這個方法可以通過簡單的幾行代碼完成jstack的大部分功能。

 

java的一些命令行工具,可以自行google,這種東西沒必要記,只需要在大腦里有印象即可。

 

介紹兩個可視化工具

jhsdb,這個工具貌似只有openjdk才有。

 

案例分析。

/**
 * staticObj、instanceObj、localObj存放在哪里?
 */
public class JHSDBTestCase {

    static class Test {
        static ObjectHolder staticObj = new ObjectHolder();
        ObjectHolder instanceObj = new ObjectHolder();

        void foo() {
            ObjectHolder localObj = new ObjectHolder();
            System.out.println("done");    // 這里設一個斷點
        }
    }

    private static class ObjectHolder {}

    public static void main(String[] args) {
        Test test = new JHSDBTestCase.Test();
        test.foo();
    }
}

這個不用工具分析也可以知道,staticObj隨着Test的類型信息存放在方法區,instanceObj隨着Test的對象實例存放在Java堆,localObject則是存放在foo()方法棧幀的局部變量表中。

 

這里我們用工具分析

1.命令行進入圖形化界面

jhsdb hsdb --pid 11180(你當前運行的線程)

 

2.點擊菜單中的Tools->Heap Parameters[插圖],結果如圖4-5所示,因為筆者的運行參數中指定了使用的是Serial收集器,圖中我們看到了典型的Serial的分代內存布局,Heap Parameters窗口中清楚列出了新生代的Eden、S1、S2和老年代的容量(單位為字節)以及它們的虛擬內存地址起止范圍。

 

3.使用scanoops命令在Java堆的新生代(從Eden起始地址到To Survivor結束地址)范圍內查找ObjectHolder的實例,結果如下所示:

 

 

可見這三個對象全部落在了新生代Eden,我們繼續分析,再使用revptrs

 

這個命令大致的作用就是通過反推實例地址,然后我們再用Tool里的inspector工具

 

 JDK 7及其以后版本的HotSpot虛擬機選擇把靜態變量與類型在Java語言一端的映射Class對象存放在一起,存儲於Java堆之中,從我們的實驗中也明確驗證了這一點[插圖]。

 

然后第二個對象

 

這次找到一個類型為JHSDB_TestCase$Test的對象實例,在Inspector中該對象實例顯示如圖4-8所示。

 

 

 第三個方法棧卻不行了。

看來revptrs命令並不支持查找棧上的指針引用,不過沒有關系,得益於我們測試代碼足夠簡潔,人工也可以來完成這件事情。在Java Thread窗口選中main線程后點擊Stack Memory按鈕查看該線程的棧內存,如圖4-9所示。

 

 肉眼看!

 

參考周志明老師《深入理解Java虛擬機》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM