通过HSDB讨论Java虚拟机运行时对象存放位置

本机环境:Windows10 jdk1.8

本文参考书本《深入理解Java虚拟机》第四章


1 这边直接把书中的代码拿过来了(请看下注释)

//  注意这里的包名路径,后面会用到
package vip.mate.module.accounting.controller;

public class JHSDB_TestCase {

    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 JHSDB_TestCase.Test();
        test.foo();
    }
}
	staticObj 存在Java静态变量的地方,概念上在JVM的方法区里
	instanceObj 是新创建的对象,肯定在堆中分配内存
	localObj 是foo()方法的局部变量(只有执行到此方法,该变量才会存在,所以需要在代码中的这边打断点)

2 debugge启动JHSDB_TestCase类(打断点,保证三个变量已经在内存中分配好)

为了加快在内存中的搜索对象的速度,我们限制以下java堆大小

-Xmx20m -XX:+UseSerialGC -XX:-UseCompressedOops

在这里插入图片描述


3 打开cmd,输入 jps-l,如下图,找到JHSDB_TestCase类的pid

在这里插入图片描述


4 下面启动HSDB,紧接着在上面cmd中输入以下命令,此时会弹出HSDB的图形化界面如下

java -classpath "%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.HSDB

在这里插入图片描述


5 从菜单里选择File -> Attach to HotSpot process

在这里插入图片描述


5 把刚才cmd中的查到的pid输入进来,点击ok

在这里插入图片描述


6 现在就连接到我们的目标进程了

在这里插入图片描述


7 现在就连接到我们的目标进程了,直接在菜单里选择Windows -> Console,会得到一个空白的Command Line窗口,在里面敲一下回车就会出现hsdb>提示符。

在这里插入图片描述


8 通过universe命令来查看GC堆的地址范围和使用情况


hsdb> universe
Heap Parameters:
Gen 0:   eden [0x0000000012800000,0x0000000012b93598,0x0000000012d60000) space capacity = 5636096, 66.52250068132267 used
  from [0x0000000012e00000,0x0000000012e9fff8,0x0000000012ea0000) space capacity = 655360, 99.998779296875 used
  to   [0x0000000012d60000,0x0000000012d60000,0x0000000012e00000) space capacity = 655360, 0.0 usedInvocations: 1

Gen 1:   old  [0x0000000012ea0000,0x0000000012ff4608,0x0000000013c00000) space capacity = 14024704, 9.940915687061915 usedInvocations: 0

hsdb> 

在这里插入图片描述

	GC堆由young gen(年轻代)和old gen(老年代)构成
	年轻代又由一个eden(伊甸区)和两个survivor space(幸存区)构成

9 通过scanoops命令查看三个对象的具体位置

注:这里提到“内存地址”是指虚拟内存意义上的地址,不是“物理内存地址”

// 这里包名一定要写全
scanoops 0x0000000012800000 0x0000000012d60000 vip.mate.module.accounting.controller.JHSDB_TestCase$ObjectHolder

在这里插入图片描述

注意上图圈红的地方,我是直接在eden区间范围搜索的,三个对象在这分配了地址


验证

1 根据对象实例地址找出引用他们的指针(revptrs 命令)

revptrs 0x0000000012b7c710

这里找到一个引用该对象的地方,是在一个java.lang.Class的实例里,并且给出了实例地址,下图圈红的地方

在这里插入图片描述


2 通过Tools -> Inspector功能再确认以下这三个地址中存放的对象

在这里插入图片描述


3 前两个对象可以重复上面两步,当我们通过以上命令验证第三个对象的时候,JHSDB返回了一个null,所以revptrs 命令不支持查找栈上的引用

在这里插入图片描述


4 我们人工来查找这第三个对象,在Java Thread窗口选中main线程后点击Stack Memory按钮查看该线程栈内存,如下图

在这里插入图片描述
以下文字来自书本:
这个线程只有两个方法栈帧,尽管没有查找功能,但通过肉眼观察地址
ox0000000002fef678上的值正好就是0x0000000012b7c748,而且JHSDB在旁边已经自动生成注释,说明这里确实是引用了一个来自新生代的JHSDB_TestCase$ObjectHolder。至此,本实验中的三个对象均已找到,并成功追溯到引用他们的地方。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值