31 Method & ConstMethod 的内存布局
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了31 Method & ConstMethod 的内存布局相关的知识,希望对你有一定的参考价值。
前言
呵呵 R大的 经典文章 : 借HSDB来探索HotSpot VM的运行时数据
另外就是 文章中提到的 根据 Method 查看方法的字节码信息, 这部分也还是挺有趣的, 我应该是 之前整理在 文档上面了的吧, 借此机会整理一下
知道这个东西的好处 就是在 "恶劣" 的调试环境下面, 给你一个 memory viewer, 你就能很快的定位到自己需要的东西, 就好比 这里有一个 Method*, 你怎么定位到 这个 方法的名字 等等, 诸如此类
就好比这的 29 加载多个JdbcDriver造成死锁 运行时汇编的调试 部分的调试场景
测试用例
package com.hx.test03;
/**
* CloneCallObjectConstructor
*
* @author Jerry.X.He <970655147@qq.com>
* @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\\x81H"
_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 的对象的初始化等等
完
参考
以上是关于31 Method & ConstMethod 的内存布局的主要内容,如果未能解决你的问题,请参考以下文章
在 button_to 中使用 :method => delete 的目的是啥?
spring 之 lookup-method & replace-method
了解 [ClassOne, ClassTwo].each(&:my_method) [重复]