使用HSDB探索JVM運行時數據

先看一段代碼
Test.java:java

public class Test {  
    static Test2 t1 = new Test2();  
           Test2 t2 = new Test2();  
    public void fn() {  
        Test2 t3 = new Test2();       
    }  
}   
class Test2 {  
  
}

Main.java:jvm

public class Main {  
    public static void main(String[] args) {  
        Test test = new Test();  
        test.fn();  
    }  
}
衆所周知執行Main類中的main方法會在java
heap中生成三個Test2類的實例:t1,t2,t3和一個Test類的實例:test。那麼這四個對象在javaheap中是如何佈局的呢?下面咱們使用HSDB來一探究竟。想要查看jvm運行時數據咱們須要使程序恰好運行完 test.fn暫停下來。平時可能咱們使用Eclipse,IDEA等各類IDE來調試,爲減小對外部工具的依賴,咱們使用Oracle JDK自帶的工具jdb來完成次任務

1、啓動jdb調試程序:

  1. 使用:jdb -XX:+UseSerialGC -Xmx10m 啓動jdb(命令的含義是使用SerialGC,同時設置java heap的大小10m)
  2. 使用:stop in Test.fn Test的在方法fn處設置斷點
  3. 使用:run Main 指定主類,啓動java程序
  4. 使用:next 向前執行一步

clipboard.png

2、啓動HSDB

  • 一、使用:java -cp sa-jdi.jar sun.jvm.hotspot.HSDB啓動HSDB

clipboard.png

  • 二、使用jps查看第一部中啓動的java程序的pid

clipboard.png

  • 三、在HSDB可視化界面的菜單裏選擇File -> Attach to HotSpot
    process,在彈出的對話框中輸入上一步找到的pid,點擊Ok就鏈接到目標程序了

clipboard.png

默認打開的窗口是java Threads窗口,顯示的是線程列表,雙擊表明線程的行會打開Oop Inspector窗口,顯示HotSpot VM裏記錄線程的一些基本信息的C++對象的內容工具

clipboard.png
選中java Threads Name 等於Main一行,而後點擊Java Threads窗口工具欄中從左數第二個按鈕能夠打開Stack Memory窗口來查看main線程的棧:oop

clipboard.png

Stack Memory窗口有三列:
左起第一列是內存地址,本文中所提到的內存地址都是虛擬內存地址不是物理內存地址
左起第二列是該地址上存儲的數據,以字寬爲單位,本文例子中是在Windows 7 64-bit上跑64位的JDK7的HotSpot VM,字寬是64位(8字節)
左起第三列是對數據註釋,豎線是範圍,橫線或斜線是鏈接範圍和註釋文字佈局

3、下面讓咱們打開HSDB裏的控制檯來使用命令瞭解更多信息

在HSDB界面選擇:Window -> Control就能夠打開HSDB的控制檯了,敲一下回車就能夠看見hsdb>提
示符,此時就可使用命令來查看更多詳細信息了:spa

clipboard.png
不知道有哪些命令,能夠試試help:線程

clipboard.png

  • 一、使用universe命令查看GC heap的使用範圍和使用狀況

clipboard.png
這裏咱們能夠很清晰的看到GC堆由:Young Gen 和 Old Gen構成,還能夠看到各區的初始大小和使用狀況調試

  • 二、使用`scanoops命令查看指定類型的實例,scanoops命令接收兩個必填參數和一個可選參數:必填參數是要掃描的地址範圍,一個是起始地址一個結束地址,可選參數是要掃描什麼類型的實例。實際掃描中會掃到指定類型及其派生類的實例。

    在咱們的java代碼中當執行完test.fn時應該建立了三個Test2的實例和一個Test的實例,那麼他們都在那呢?下面讓咱們用scanoops命令來把他們找出來:code

clipboard.png
clipboard.png
這裏能夠看出確實掃描出了三個Test2類型的實例和一個Test類型的實例,內容有兩列:左列是實例的起始地址,右列是實例的實際類型。從它們的起始地址,對照前面使用universe命令看到的GC堆的地址範圍,能夠看出他們都在Eden裏。對象

  • 三、使用whatis命令能夠進一步看到它們都分配到了main線程的Thread-local Allocation Buffer中:

clipboard.png

  • 四、還可使用inspect命令查看對象的內容:

clipboard.png
1> instance of Oop for Test: 代表該地址表明的對象是Test類的實例
2> _mark: 對象頭的第一個字段記錄對象的狀態
3> _metadata._compressed_klass: 指向描述Test類信息的對象
4> t2:Oop for Test2: 該實例的字段t2是Test2的實例

  • 五、使用mem能夠看更直接的數據,接受的兩個參數,起始地址和以字寬爲單位的「長度」

hsdb> mem 0x00000000ff6de2e0 20x00000000ff6de2e0: 0x0000000000000001 // _mark0x00000000ff6de2f8: 0x0000000011ba0418 // _metadata._compressed_klass

相關文章
相關標籤/搜索