使用HSDB探索JVM运行时数据

先看一段代码
Test.java:

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

Main.java:

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来完成次任务

一、启动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

二、启动HSDB

  • 1、使用:java -cp sa-jdi.jar sun.jvm.hotspot.HSDB启动HSDB

clipboard.png

  • 2、使用jps查看第一部中启动的java程序的pid

clipboard.png

  • 3、在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线程的栈:

clipboard.png

Stack Memory窗口有三列:
左起第一列是内存地址,本文中所提到的内存地址都是虚拟内存地址不是物理内存地址
左起第二列是该地址上存储的数据,以字宽为单位,本文例子中是在Windows 7 64-bit上跑64位的JDK7的HotSpot VM,字宽是64位(8字节)
左起第三列是对数据注释,竖线是范围,横线或斜线是连接范围和注释文字

三、下面让我们打开HSDB里的控制台来使用命令了解更多信息

在HSDB界面选择:Window -> Control就可以打开HSDB的控制台了,敲一下回车就可以看见hsdb>提
示符,此时就可以使用命令来查看更多详细信息了:

clipboard.png
不知道有哪些命令,可以试试help:

clipboard.png

  • 1、使用universe命令查看GC heap的使用范围和使用情况

clipboard.png
这里我们可以很清晰的看到GC堆由:Young Gen 和 Old Gen构成,还可以看到各区的初始大小和使用情况

  • 2、使用`scanoops命令查看指定类型的实例,scanoops命令接收两个必填参数和一个可选参数:必填参数是要扫描的地址范围,一个是起始地址一个结束地址,可选参数是要扫描什么类型的实例。实际扫描中会扫到指定类型及其派生类的实例。

    在我们的java代码中当执行完test.fn时应该创建了三个Test2的实例和一个Test的实例,那么他们都在那呢?下面让我们用scanoops命令来把他们找出来:

clipboard.png
clipboard.png
这里可以看出确实扫描出了三个Test2类型的实例和一个Test类型的实例,内容有两列:左列是实例的起始地址,右列是实例的实际类型。从它们的起始地址,对照前面使用universe命令看到的GC堆的地址范围,可以看出他们都在Eden里。

  • 3、使用whatis命令可以进一步看到它们都分配到了main线程的Thread-local Allocation Buffer中:

clipboard.png

  • 4、还可以使用inspect命令查看对象的内容:

clipboard.png
1> instance of Oop for Test: 表明该地址代表的对象是Test类的实例
2> _mark: 对象头的第一个字段记录对象的状态
3> _metadata._compressed_klass: 指向描述Test类信息的对象
4> t2:Oop for Test2: 该实例的字段t2是Test2的实例

  • 5、使用mem可以看更直接的数据,接受的两个参数,起始地址和以字宽为单位的“长度”

hsdb> mem 0x00000000ff6de2e0 2
0x00000000ff6de2e0: 0x0000000000000001 // _mark
0x00000000ff6de2f8: 0x0000000011ba0418 // _metadata._compressed_klass

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值