前言

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

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

知道这个东西的好处 就是在 "恶劣" 的调试环境下面, 给你一个 memory viewer, 你就能很快的定位到自己需要的东西, 就好比 这里有一个 Method*, 你怎么定位到 这个 方法的名字 等等, 诸如此类 

就好比这的 29 加载多个JdbcDriver造成死锁 运行时汇编的调试 部分的调试场景 

测试用例

package com.hx.test03;

/**
 * CloneCallObjectConstructor
 *
 * @author Jerry.X.He 
 * @version 1.0
 * @date 2019-12-29 14:41
 */
public class Test05CloneCallObjectConstructor implements Cloneable {

  // Test05CloneCallObjectConstructor
  public static void main(String[] args) throws Exception {

    Test05CloneCallObjectConstructor obj = new Test05CloneCallObjectConstructor();
    Test05CloneCallObjectConstructor cloned = (Test05CloneCallObjectConstructor) obj.clone();

    System.out.println(obj == cloned);

  }

}

对应的字节码信息如下, 下面参照可能需要使用到 

master:classes jerry$ javap -c com/hx/test03/Test05CloneCallObjectConstructor.class 
Compiled from "Test05CloneCallObjectConstructor.java"
public class com.hx.test03.Test05CloneCallObjectConstructor implements java.lang.Cloneable {
  public com.hx.test03.Test05CloneCallObjectConstructor();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: new           #2                  // class com/hx/test03/Test05CloneCallObjectConstructor
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method java/lang/Object.clone:()Ljava/lang/Object;
      12: checkcast     #2                  // class com/hx/test03/Test05CloneCallObjectConstructor
      15: astore_2
      16: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      19: aload_1
      20: aload_2
      21: if_acmpne     28
      24: iconst_1
      25: goto          29
      28: iconst_0
      29: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
      32: return
}

Method 的内存布局 

(lldb) x 0x108a67fb8 -c 0x100
0x108a67fb8: 40 6f 63 07 01 00 00 00 00 00 00 00 00 00 00 00  @oc.............
0x108a67fc8: 28 7f a6 08 01 00 00 00 00 00 00 00 00 00 00 00  (...............
0x108a67fd8: 00 00 00 00 00 00 00 00 09 00 00 00 fe ff ff ff  ................
0x108a67fe8: 00 00 00 00 00 00 00 00 00 a7 67 0e 01 00 00 00  ..........g.....
0x108a67ff8: 9a 45 7f 0e 01 00 00 00 00 00 00 00 00 00 00 00  .E..............
0x108a68008: 00 a7 67 0e 01 00 00 00 29 00 00 00 00 02 ff 00  ..g.....).......

_value = {Method * | 0x108a67fb8} 0x0000000108a67fb8
 Metadata = {Metadata}
 _constMethod = {ConstMethod * | 0x108a67f28} 0x0000000108a67f28
 _method_data = {MethodData * | 0x0} NULL
 _method_counters = {MethodCounters * | 0x0} NULL
 _access_flags = {AccessFlags}
 _vtable_index = {int} -2
 _intrinsic_id = {u2} 0
 _flags = {u2} 0
 _compiled_invocation_count = {int} 0
 _i2i_entry = {address | 0x10e67a700} "H\x8bS\x10\x0f\xb7J4\x0f\xb7R2+с��
 _from_compiled_entry = {address | 0x10e7f459a} "H\x81{H"
 _code = {CompiledMethod *volatile | 0x0} NULL
 _from_interpreted_entry = {address | 0x10e67a700} "H\x8bS\x10\x0f\xb7J4\x0f\xb7R2+с��

&(method())._valid = 0x108a67fc0
&(method())._constMethod = 0x108a67fc8
&(method())._method_data = 0x108a67fd0
&(method())._method_counters = 0x108a67fd8
&(method())._access_flags = 0x108a67fe0
&(method())._vtable_index = 0x108a67fe4
&(method())._intrinsic_id = 0x108a67fe8
&(method())._flags = 0x108a67fea
&(method())._compiled_invocation_count = 0x108a67fec
&(method())._i2i_entry = 0x108a67ff0
&(method())._from_compiled_entry = 0x108a67ff8
&(method())._code = 0x108a68000
&(method())._from_interpreted_entry = 0x108a68008

ConstMethod 的内存布局

(lldb) x 0x108a67f28 -c 0x100
0x108a67f28: 3d 15 00 00 00 00 00 00 68 7c a6 08 01 00 00 00  =.......h|......
0x108a67f38: 10 80 a6 08 01 00 00 00 e0 44 00 a5 f5 7f 00 00  .........D......
0x108a67f48: 12 00 00 00 07 00 0e 00 21 00 10 00 11 00 01 00  ........!.......
0x108a67f58: 03 00 03 00 01 00 01 00 bb 00 02 59 b7 01 00 4c  ...........Y...L
0x108a67f68: 2b b6 02 00 c0 00 02 4d b2 03 00 2b 2c a6 00 07  +......M...+,...
0x108a67f78: 04 a7 00 04 03 b6 04 00 b1 ff 00 1e 41 42 82 00  ............AB..
0x108a67f88: 00 00 00 00 00 00 00 00 21 00 12 00 13 00 00 00  ........!.......
0x108a67f98: 00 00 08 00 19 00 14 00 0f 00 00 00 01 00 10 00  ................
0x108a67fa8: 11 00 15 00 0f 00 00 00 02 00 03 00 1b 00 01 00  ................

_constMethod = {ConstMethod * | 0x108a67f28} 0x0000000108a67f28
 _fingerprint = {uint64_t} 5437
 _constants = {ConstantPool * | 0x108a67c68} 0x0000000108a67c68
 _stackmap_data = {Array<unsigned char> * | 0x108a68010} 0x0000000108a68010
  = {ConstMethod::(anonymous union)} 
 _constMethod_size = {int} 18
 _flags = {u2} 7
 _result_type = {u1} 14 '\x0e'
 _code_size = {u2} 33
 _name_index = {u2} 16
 _signature_index = {u2} 17
 _method_idnum = {u2} 1
 _max_stack = {u2} 3
 _max_locals = {u2} 3
 _size_of_parameters = {u2} 1
 _orig_method_idnum = {u2} 1

&(method()->_constMethod)._fingerprint = 0x0000000108a67f28
&(method()->_constMethod)._constants = 0x0000000108a67f30
&(method()->_constMethod)._stackmap_data = 0x0000000108a67f38
&(method()->_constMethod)._adapter = 0x0000000108a67f40
&(method()->_constMethod)._adapter_trampoline = 0x0000000108a67f40
&(method()->_constMethod)._constMethod_size = 0x0000000108a67f48
&(method()->_constMethod)._flags = 0x0000000108a67f4c
&(method()->_constMethod)._result_type = 0x0000000108a67f4e
&(method()->_constMethod)._code_size = 0x0000000108a67f50
&(method()->_constMethod)._name_index = 0x0000000108a67f52
&(method()->_constMethod)._signature_index = 0x0000000108a67f54
&(method()->_constMethod)._method_idnum = 0x0000000108a67f56
&(method()->_constMethod)._max_stack = 0x0000000108a67f58
&(method()->_constMethod)._max_locals = 0x0000000108a67f5a
&(method()->_constMethod)._size_of_parameters = 0x0000000108a67f5c
&(method()->_constMethod)._orig_method_idnum = 0x0000000108a67f5e
(method()->_constMethod)->code_base() = 0x0000000108a67f60

(method()->_constMethod)->code_base()
0x0000000108a67f60 : bb 00 02 : new           #2
0x0000000108a67f63 : 59 : dup
0x0000000108a67f64 : b7 01 00 : invokespecial #1
0x0000000108a67f67 : 4c : astore_1
0x0000000108a67f68 : 2b : aload_1
0x0000000108a67f69 : b6 02 00 : invokevirtual #2
0x0000000108a67f6c : c0 00 02 : checkcast     #2
0x0000000108a67f6f : 4d : astore_2
0x0000000108a67f70 : b2 03 00 : getstatic     #3
0x0000000108a67f73 : 2b : aload_1
0x0000000108a67f74 : 2c : aload_2
0x0000000108a67f75 : a6 00 07 : if_acmpne     28
0x0000000108a67f78 : 04 : iconst_1
0x0000000108a67f79 : a7 00 04 : goto          29
0x0000000108a67f7c : 03 : iconst_0
0x0000000108a67f7d : b6 04 00 : invokevirtual #6
0x0000000108a67f80 : b1 : return

0x108a67f81 : linenumber_table : ff 00 1e 41 42 82 00
	ff 00 1e : escape : 0xff, bci : 00(0 << 1), line : 30(15 << 1)
   		line 15: 0
	41 : 0x0100 0001 : bci : 8, line : 1
		line 16: 8
	42 : 0x0100 0010 : bci : 8, line : 2
		line 18: 16
	82 : 0x1000 0010 : bci : 16, line : 2
		line 20: 32
	00 : end of stream

0x108a67f88 : 00 00 00 00 00 00 : align padding bytes
0x108a67f8e : local_variable_table : 00 00 21 00 12 00 13 00 00 00 00 00[0, 33, 18, 19, 0, 0]
 									 08 00 19 00 14 00 0f 00 00 00 01 00[8, 25, 20, 15, 0, 1]
 									 10 00 11 00 15 00 0f 00 00 00 02 00[16, 17, 21, 15, 0, 2]
        // LocalVariableTableElement's structure
        u2 start_bci;
        u2 length;
        u2 name_cp_index;
        u2 descriptor_cp_index;
        u2 signature_cp_index;
        u2 slot;
        // parsed
        LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      33     0  args   [Ljava/lang/String;
            8      25     1   obj   Lcom/hx/test03/Test05CloneCallObjectConstructor;
           16      17     2 cloned   Lcom/hx/test03/Test05CloneCallObjectConstructor;
0x108a67fb2 : 03 00 : local_variable_length
0x108a67fb4 : 1b 00 : checked exception
0x108a67fb6 : 01 00 : checked_exceptions_length


constMethods 中的几个数据的排列 : method_parameters_length_addr, checked_exceptions_length_addr, exception_table_length_addr, localvariable_table_length_addr 详情请参见 constMethod.cpp 里面的这几个方法
localvariable_table, exception_table, check_exception_table, method_parameter, method_parameter 是基于 last_u2_element

linenumber_table 是 codebase + codesize, 存放在 code 后面, linenumber_table 和 上面一系列 *_table 之间如果存在未使用的字节, 便是 align padding bytes
在 classFileParser. parse_method 里面存在 Method 的 size 的计算, constMethod 的 size 的计算 等等, 以及 Method 的对象的初始化等等

完 

参考

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