使用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

相关文章
相关标签/搜索