前言

呵呵 R大的 经典文章 : 借HSDB来探索HotSpot VM的运行时数据 

也来 动手实际过一次 

另外就是 文章中提到的 根据 Method 查看方法的字节码信息, 这部分也还是挺有趣的, 我应该是 之前整理在 文档上面了的吧, 多久整理一下 

测试用例

package com.hx.test03;

/**
 * HSDBInspectClass
 *
 * @author Jerry.X.He 
 * @version 1.0
 * @date 2020-02-01 16:30
 */
public class Test16HSDBInspectClass {

  // static instanceClass & instanceClass
  private static InstanceClass staticInstance = new InstanceClass("staticInstance");
  private InstanceClass instance = new InstanceClass("instance");

//  三个 Test16HSDBInspectClass$InstanceClass 实例
//  0x000000079591fd38	Oop for com/hx/test03/Test16HSDBInspectClass$InstanceClass	InstanceKlass for com/hx/test03/Test16HSDBInspectClass$InstanceClass
//  0x000000079591fdb0	Oop for com/hx/test03/Test16HSDBInspectClass$InstanceClass	InstanceKlass for com/hx/test03/Test16HSDBInspectClass$InstanceClass
//  0x000000079591fdf8	Oop for com/hx/test03/Test16HSDBInspectClass$InstanceClass	InstanceKlass for com/hx/test03/Test16HSDBInspectClass$InstanceClass

  // Test16HSDBInspectClass
//  hsdb> revptrs 0x000000079591fd38
//  Computing reverse pointers...
//  Done.
//null
//  Oop for java/lang/Class @ 0x00000007959170d0
//  hsdb> revptrs 0x000000079591fdb0
//  Oop for com/hx/test03/Test16HSDBInspectClass @ 0x000000079591fda0
//  hsdb> revptrs 0x000000079591fdf8
//          null
//          null
//  hsdb>
  // 可以找到 静态变量 和 局部变量, revptrs 找不到 栈帧上面这一个
  // 但是可以从 main 方法的栈帧信息里面看到对应的 引用
//  hsdb> mem 0x000070000225f908
//          0x000070000225f908: 0x000000079591fdf8
  // 三个实例的三个引用, 一个在 instanceKlass 的 java_mirror 里面, 另外一个在新建的实例 thisInstance 里面, 一个在 栈帧上面
  public static void main(String[] args) {

    foo();

  }

  // local instanceClass
  public static void foo() {
    Test16HSDBInspectClass thisInstance = new Test16HSDBInspectClass();
    InstanceClass localInstance = new InstanceClass("localInstance");
    System.out.println(" break point ");
  }

  /**
   * InstanceClass
   *
   * @author Jerry.X.He <970655147@qq.com>
   * @version 1.0
   * @date 2020-02-01 16:33
   */
  private static class InstanceClass {
    private String str;
    public InstanceClass(String str) {
      this.str = str;
    }
  }

}

在 foo 方法里面 下图的地方打上一个断点 

30 借HSDB来探索HotSpot VM的运行时数据_object

基于 HSDB 的可视化调试

jps 查看当前进程 pid 

启动 hsdb, 连接到 当前进程 

Tool >> Object Histogram 查看 Test16HSDBInspectClass$InstanceClass 的信息, 可以发现 三个实例, 我们依次看下 这三个实例 

30 借HSDB来探索HotSpot VM的运行时数据_字节码_02

第一个是 Test16HSDBInspectClass.staticInstance, 被在 Test16HSDBInspectClass.class 对应的 oop 引用

30 借HSDB来探索HotSpot VM的运行时数据_d3_03

第二个是被一个 Test16HSDBInspectClass 实例引用, 这个 Test16HSDBInspectClass 实例被 main线程 栈上的引用 所引用 

30 借HSDB来探索HotSpot VM的运行时数据_object_04

第三个是被 main线程 栈上的引用 所引用 

30 借HSDB来探索HotSpot VM的运行时数据_vm_05

基于 HSDB 命令行的调试

再来通过 revptrs 来看下 引用这三个 实例的情况呢 

revptrs 0x00000007bf07cba0
null
Oop for java/lang/Class @ 0x00000007bf073b58
hsdb> inspect 0x00000007bf073b58
instance of Oop for java/lang/Class @ 0x00000007bf073b58 @ 0x00000007bf073b58 (size = 112)
<<Reverse pointers>>: 
staticInstance: Oop for com/hx/test03/Test16HSDBInspectClass$InstanceClass @ 0x00000007bf07cba0 Oop for com/hx/test03/Test16HSDBInspectClass$InstanceClass @ 0x00000007bf07cba0

hsdb> revptrs 0x00000007bf07cc18
Oop for com/hx/test03/Test16HSDBInspectClass @ 0x00000007bf07cc08
hsdb> inspect 0x00000007bf07cc08
instance of Oop for com/hx/test03/Test16HSDBInspectClass @ 0x00000007bf07cc08 @ 0x00000007bf07cc08 (size = 16)
<<Reverse pointers>>: 
_mark: 1
_metadata._compressed_klass: InstanceKlass for com/hx/test03/Test16HSDBInspectClass
instance: Oop for com/hx/test03/Test16HSDBInspectClass$InstanceClass @ 0x00000007bf07cc18 Oop for com/hx/test03/Test16HSDBInspectClass$InstanceClass @ 0x00000007bf07cc18

hsdb> revptrs 0x00000007bf07cc60
null
null
hsdb>

在 main线程 栈中的这个 Test16HSDBInspectClass$InstanceClass 实例, revptrs 扫描不到对应的引用, 呵呵 R大 似乎是说明了一下 原因吧

不过 好在至少我们有一个完善的方法 能够找到 引用这个实例 的引用 

栈帧信息

从 hsdb 上面截取栈帧信息如下图 

30 借HSDB来探索HotSpot VM的运行时数据_vm_06

我们详细的拆分一下 main, foo 方法的栈帧的相关信息 如下  

0x00007000070d28b8	0x00007000070d28b8 : expression bottom
0x00007000070d28c0	0x0000000119ce507a : byte code pointer
0x00007000070d28c8	0x00007000070d2910 : pointer to locals
0x00007000070d28d0	0x0000000119ce51d0 : constants pool cache
0x00007000070d28d8	0x0000000000000000 : method data oop
0x00007000070d28e0	0x0000000119ce50a8 : method oop
0x00007000070d28e8	0x0000000000000000 : last java stack pointer
0x00007000070d28f0	0x00007000070d2918 : old stack pointer
0x00007000070d28f8	0x00007000070d2958 : old frame pointer
0x00007000070d2900	0x000000010a8dd35d : return address[entry_point's address]
0x00007000070d2908	0x00000007bf07cc60 : localInstance
0x00007000070d2910	0x00000007bf07cc08 : thisInstance
-------------------------------------- foo -------------------------------------------
0x00007000070d2918	0x00007000070d2918 : expression bottom
0x00007000070d2920	0x0000000119ce4fc8 : byte code pointer
0x00007000070d2928	0x00007000070d2968 : pointer to locals
0x00007000070d2930	0x0000000119ce51d0 : constants pool cache
0x00007000070d2938	0x0000000000000000 : method data oop
0x00007000070d2940	0x0000000119ce4fe0 : method oop
0x00007000070d2948	0x00007000070d2918 : last java stack pointer
0x00007000070d2950	0x00007000070d2968 : old stack pointer
0x00007000070d2958	0x00007000070d29d0 : old frame pointer
0x00007000070d2960	0x000000010a8d57a7 : return address[entry_point's address]
0x00007000070d2968	0x00000007bf07cbf8 : args
-------------------------------------- main -------------------------------------------

这里可以 清晰的 看到 第三个 Test16HSDBInspectClass$InstanceClass 的引用 

完 

参考

借HSDB来探索HotSpot VM的运行时数据