前言
在《openjdk的启动流程》一文,create_vm方法中
initialize_class(vmSymbols::java_lang_Thread(), CHECK_0);//装载threadClass
oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0);//创建第一个thread对象
在《JVM内存模型》中探讨过,Java对象在内存中是实例数据和类型数据相分离的,实例数据保存了一个指向类型数据的指针,而虚拟机中用oop-klass二分模型很好的进行实现 。
二分模型
Oop表示Java实例,主要用于表示实例数据,不提供任何虚函数功能,Oop保存了对应Kclass的指针,所有方法调用通过Klass完成并通过Klass获取类型信息,Klass基于C++的虚函数提供对Java多态的支持。Klass作为父类主要职责是描述了类的继承关系。
klass
MetaspaceObj #类是作为存放在Metaspace元空间的中类的基类
└───Metadata #内部表示类相关元数据的一个基类
│ └───Klass #普通类模板
│ │ └───ArrayKlass #数组类模板
│ │ │ └───TypeArrayKlass #基本类型数组
│ │ │ └───ObjArrayKlass #类数组或者多维数组
│ │ └───InstanceKlass #类实例
│ │ │ └───InstanceClassLoaderKlass #加载器类实例
│ │ │ └───InstanceMirrorKlass #监控类实例
│ │ │ └───InstanceRefKlass #引用类实例
/**---------------Klass------------------**/
//如果不是InstanceKlass或者ArrayKlass,则该值为0
//对InstanceKclass而言,该值表示对象的以字节为单位的内存占用空间
//对ArrayKlass而言,该值是一个组合起来的假数字,包含4部分,具体怎么组合和解析由子类实现:
// tag:如果数组元素是对象实例则是0x80,否则是0xC0
// hsz: 数组头元素的字节数
// ebt:数组元素的类型,枚举值BasicType
// esz:数组元素大小,以字节为单位
//该值因为被频繁查询,所以放在虚函数表指针的后面。
jint _layout_helper;
//用于快速定位的父类
//如果此klass表示的是接口,则定位到&_secondary_super_cache
//如果此klass表示的是类,则定位到&_primary_supers[depth()],就是_primary_supers的最后一位
juint _super_check_offset;
//类名.
//Instance classes: java/lang/String,
//Array classes: [I,[Ljava/lang/String;
//Set to zero for all other kinds of classes.
Symbol* _name;
// Klass指针,上一次查找过的接口
Klass* _secondary_super_cache;
//所有接口的接口
Array<Klass*>* _secondary_supers;
//默认继承的类列表,如Object
Klass* _primary_supers[_primary_super_limit];
// java/lang/Class 的实例 mirroring this class
oop _java_mirror;
// 父类
Klass* _super;
// First subclass (NULL if none); _subklass->next_sibling() is next one
//子类头节点
Klass* _subklass;
// Sibling link (or NULL); links all subklasses of a klass
//串连所有子类,形成链表
Klass* _next_sibling;
// All klasses loaded by a class loader are chained through these links
//ClassLoader加载的下一个Klass
Klass* _next_link;
//此类对应的ClassLoader
ClassLoaderData* _class_loader_data;
//修改标识,Class.getModifiers使用
jint _modifier_flags;
//获取类的修饰符,如private类访问控制,final,static,abstract ,native等
AccessFlags _access_flags;
/**---------------Klass------------------**/
/**---------------InstanceKlass------------------**/
//该类使用的所有注解
Annotations* _annotations;
//该类的数组Klass
Klass* _array_klasses;
// 类的常量池
ConstantPool* _constants;
//内部类
//The InnerClasses attribute and EnclosingMethod attribute.
//If the class has InnerClasses attribute
//1.inner_class_info_index
//2.outer_class_info_index
//3.inner_name_index
//4.inner_class_access_flags
//If the EnclosingMethod attribute exists,
//1.class_index
//2.method_index
//If only the InnerClasses attribute exists
// the _inner_classes array length is number_of_inner_classes * 4.
// If the class has both InnerClasses and EnclosingMethod attributes
//the _inner_classes array length is number_of_inner_classes * 4 + enclosing_method_attribute_size.
Array<jushort>* _inner_classes;
// the source debug extension for this klass, NULL if not specified.
// Specified as UTF-8 string without terminating zero byte in the classfile,
// it is stored in the instanceklass as a NULL-terminated UTF-8 string
char* _source_debug_extension;
//根据类名计算的以该类的数组的名字
Symbol* _array_name;
//非静态字段的内存大小,以heapOopSize为单位,默认使用压缩指针时heapOopSize是int的大小
// Number of heapOopSize words used by non-static fields in this klass
// (including inherited fields but after header_size()).
int _nonstatic_field_size;
//静态字段的内存大小,以字宽(HeapWordSize,实际是一个指针变量的内存大小)为单位
// number words used by static fields (oop and non-oop) in this klass
int _static_field_size;
//Generic signature在常量池中的索引
// Constant pool index to the utf8 entry of the Generic signature, or 0 if none.
u2 _generic_signature_index;
//包含此类的源文件名在常量池中索引
// Constant pool index to the utf8 entry for the name of source file
// containing this klass, 0 if not specified.
u2 _source_file_name_index;
//此类的包含的静态引用类型字段的数量
// number of static oop fields in this klass
u2 _static_oop_field_count;
//总的字段数量
// The number of declared Java fields
u2 _java_fields_count;
//非静态的oop map block的内存大小,以字宽为单位 (oop根据这个来申请内存)
//size in words of nonstatic oop map blocks
int _nonstatic_oop_map_size;
//minor version number of class file
u2 _minor_version;
//major version number of class file
u2 _major_version;
//初始化的此类Thread指针
// Pointer to current thread doing initialization (to handle recusive initialization)
Thread* _init_thread;
// Java 虚函数表(vtable)的内存大小,以字宽为单位
int _vtable_len;
// Java 接口函数表(itable)的内存大小,以字宽为单位
int _itable_len;
// OopMapCache for all methods in the klass (allocated lazily)
OopMapCache* volatile _oop_map_cache;
//MemberNameTable指针,保存了成员名
MemberNameTable* _member_names;
//NIid指针,该类的第一个静态字段的JNIid,可以根据其_next属性获取下一个字段的JNIid
JNIid* _jni_ids;
//jmethodID指针,java方法的ID列表
jmethodID* _methods_jmethod_ids;
//依赖的本地方法,以根据其_next属性获取下一个nmethod
nmethodBucket* _dependencies;
//栈上替换的本地方法链表的头元素
nmethod* _osr_nmethods_head;
//bpt lists, managed by Method*
BreakpointInfo* _breakpoints;
//class文件的内容,JVMTI retransform时使用
// JVMTI fields can be moved to their own structure - see 6315920
// JVMTI: cached class file, before retransformable agent modified it in CFLH
JvmtiCachedClassFileData* _cached_class_file;
//JVMTI: used during heap iteration
JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map;
//已经分配的方法的idnum的个数,可以根据该ID找到对应的方法,如果JVMTI有新增的方法,已分配的ID不会变
// JNI/JVMTI: increments with the addition of methods, old ids don't change
volatile u2 _idnum_allocated_count;
//类的状态,是一个枚举值ClassState,
//allocated(已分配内存),
//loaded(从class文件读取加载到内存中),
//linked(已经成功链接和校验),
//being_initialized(正在初始化),
//fully_initialized(已经完成初始化),
//initialization_error(初始化异常)
u1 _init_state;
//引用类型
u1 _reference_type;
// 方法指针数组,类方法
Array<Method*>* _methods;
// 从接口继承的默认方法
Array<Method*>* _default_methods;
// 直接实现的接口Klass
Array<Klass*>* _local_interfaces;
// 所有实现的接口Klass,包含_local_interfaces和通过继承间接实现的接口
Array<Klass*>* _transitive_interfaces;
// 保存类中方法声明时的顺序,JVMTI使用
Array<int>* _method_ordering;
//默认方法在虚函数表中的索引
// Int array containing the vtable_indices for default_methods
// offset matches _default_methods offset
Array<int>* _default_vtable_indices;
// Instance and static variable information, starts with 6-tuples of shorts
// [access, name index, sig index, initval index, low_offset, high_offset]
// for all fields, followed by the generic signature data at the end of
// the array. Only fields with generic signature attributes have the generic
// signature data set in the array. The fields array looks like following:
//
// f1: [access, name index, sig index, initial value index, low_offset, high_offset]
// f2: [access, name index, sig index, initial value index, low_offset, high_offset]
// ...
// fn: [access, name index, sig index, initial value index, low_offset, high_offset]
// [generic signature index]
// [generic signature index]
// offset = int(high_offset,low_offset) >> 2
// |---------high---------|---------low---------|
// ..........................................00 - blank
// [------------------offset----------------]01 - real field offset
// ......................[-------type-------]10 - plain field with type
// [--contention_group--][-------type-------]11 - contended field with type and contention group
Array<u2>* _fields;
//接下来几个属性是内嵌的在类中的,没有对应的属性名,只能通过指针和偏移量的方式访问:
// embedded Java vtable follows here,Java虚函数表,大小等于_vtable_len
// embedded Java itables follows here,Java接口函数表,大小等于 _itable_len
// embedded static fields follows here
// embedded nonstatic oop-map blocks follows here,非静态oop-map blocks ,大小等于_nonstatic_oop_map_size
// embedded implementor of this interface follows here
//(接口的实现类,仅当前类表示一个接口时存在,如果接口没有任何实现类则为NULL,如果只有一个实现类则为该实现类的Klass指针,如果有多个实现类,为当前类本身)
// The embedded implementor only exists if the current klass is an
// iterface. The possible values of the implementor fall into following
// three cases:
// NULL: no implementor.
// A Klass* that's not itself: one implementor.
// Itself: more than one implementors.
// embedded host klass follows here
//(只在匿名类中存在,为了支持JSR 292中的动态语言特性,会给匿名类生成一个host klass)
// The embedded host klass only exists in an anonymous class for
// dynamic language support (JSR 292 enabled). The host class grants
// its access privileges to this class also. The host class is either
// named, or a previously loaded anonymous class. A non-anonymous class
// or an anonymous class loaded through normal classloading does not
// have this embedded field.
/**---------------InstanceKlass------------------**/
Oop
oopDesc #内部实例基类
└───arrayOopDesc #内部表示类相关元数据的一个基类
│ └───objArrayOopDesc #普通类模板
│ └───typeArrayOopDesc #基本类型数组
└───instanceOopDesc #加载器类实例
└───markOopDesc #用于描述对象头
/**---------------oopDesc------------------**/
//markOopDesc是oopDesc的子类,用于描述对象头,因为保证对象状态变更在各CPU种同步,所以加volatile修饰
volatile markOop _mark;
//是一个union结构,用于表示该oopDesc关联的Klass,使用压缩指针时,就设置其中的_compressed_klass属性
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
// BarrierSet提供了屏障实现和系统其它部分之间的接口,是静态属性,必须初始化
static BarrierSet* _bs;
/**---------------oopDesc------------------**/
/**---------------markOopDesc------------------**/
//markOopDesc继承自oopDesc,用于描述对象头,
//oopDesc中的_mark属性引用的并不是一个真实存在的markOopDesc实例,它是一个32位的数组(启用指针压缩)或者64位数组(禁止指针压缩)
//注意指针压缩包含两种,Java对象类型字段的oop指针和oopDesc引用Klass的指针,分别对应两个参数UseCompressedOops和UseCompressedClassPointers
//
// 32 bits:
// --------
// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
// size:32 ------------------------------------------>| (CMS free block)
// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
// 64 bits:
// --------
// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
// PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
// size:64 ----------------------------------------------------->| (CMS free block)
//
// unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)
// JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)
// narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
// unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
/**---------------markOopDesc------------------**/
/**---------------instanceOopDesc------------------**/
//instanceOopDesc继承自oopDesc,用于表示普通的Java对象,每次new一个Java对象就会创建一个新的instanceOopDesc实例。
//该类没有添加新的属性,只是新增了两个方法.
//用于返回包含OopDesc自身属性的内存的偏移量,即该偏移量之后的内存用于保存Java对象实例属性
base_offset_in_bytes()
//用于判断是否包含指定偏移量的非静态属性。
contains_field_offset(int offset, int nonstatic_field_size)
//instanceOopDesc是如何保存Java对象实例的属性了?
//基本类型字段的实现都是在oopDesc的地址的基础上加上一个偏移量算出该字段的地址,偏移量的单位是字节,各字段的偏移量和初始值等属性都保存在InstanceKlass的_fields属性中,根据该地址可以直接获取或者设置字段值
/**---------------instanceOopDesc------------------**/
/**---------------arrayOopDesc------------------**/
// arrayOopDesc继承自oopDesc,该类是所有数组OopDesc的基类,arrayOopDesc同InstanceOopDesc的内存布局是不一样的,除OopDesc定义的属性外还需保存数组的长度,数组元素的取值。
//该类添加了几个跟数组相关的方法,如下:
//获取首元素的偏移量
int base_offset_in_bytes(BasicType type)
//获取首元素的地址
void* base(BasicType type)
//index是否数组越界
bool is_within_bounds(int index)
//获取数组的长度
int length()
//设置数组长度
void set_length(int length)
//获取数组的最大长度
int32_t max_array_length(BasicType type):
//从代码可知数组长度保存在_metadata属性的后面,类型为int,占4字节,这也决定了数组的最大长度不能超过int的最大值。
/**---------------arrayOopDesc------------------**/
/**---------------typeArrayOopDesc------------------**/
//typeArrayOopDesc继承自arrayOopDesc,用于表示数组元素是基本类型如int,long等的数组。跟InstanceOopDesc类似
/**---------------typeArrayOopDesc------------------**/
/**---------------objArrayOopDesc------------------**/
//objArrayOopDesc继承自arrayOopDesc,用于表示元素是对象的数组,包括多维数组。同typeArrayOopDesc,该类增加了根据索引获取和设置数组的方法,同样需要根据配置对指针做压缩解压缩处理
/**---------------objArrayOopDesc------------------**/
案例材料
- 实验类
package mm;
interface A{
void showA();
}
interface B{
String WWTXT = "khkh";
void showB();
}
class BaseClass implements B {
private int b;
public BaseClass(int b) {
this.b = b;
}
@Override
public void showB() {
System.out.println(b);
}
}
public class MyTest extends BaseClass implements A{
public static String TXT = "yoyo";
public static String getTXT(){
return TXT+"@bbb";
}
private int a;
private String s;
public MyTest(int a,int b) {
super(b);
this.a = a;
this.s = "test";
}
public static void main(String[] args) {
MyTest t = new MyTest(6,7);
MyTest[] gg = new MyTest[2];
gg[0] = t;
t.showA();
t.showB();
System.out.println(gg.getClass());
System.out.println(t.hashCode());
System.out.println(WWTXT);
System.out.println(getTXT());
System.out.println("end");
}
@Override
public void showA() {
System.out.println(a);
}
}
- 运行结果
6
7
class [Lmm.MyTest;
1227229563
khkh
yoyo@bbb
- sa命令
sudo java -cp .:$JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB
《Hotspot学习利器:HSDB和CLHSDB》
- 查看分区情况
universe
ParallelScavengeHeap [
PSYoungGen
[ eden = [0x0000000174380000,0x00000001746199d8,0x0000000176400000] ,
from = [0x0000000176900000,0x0000000176900000,0x0000000176e00000] ,
to = [0x0000000176400000,0x0000000176400000,0x0000000176900000]
]
PSOldGen [ [0x000000011ee00000,0x000000011ee00000,0x0000000124380000] ] ]
- 在eden中搜索mm.MyTest对象
scanoops 0x0000000174380000 0x0000000176400000 mm.MyTest
0x00000001745a6648 mm/MyTest
- 查看对象的具体数据
#因为我在JAVA类启动的时,采用-XX:-UseCompressedOops,禁用压缩格式
mem 0x00000001745a6648 8
#对照instanceOopDesc结构得
0x00000001745a6648: 0x0000004926097b01 # mark地垃
0x00000001745a6650: 0x00000001a3cad5f8 # intanceKlass地址
0x00000001745a6658: 0x0000000000000007 # 数据实例7
0x00000001745a6660: 0x0000000000000006 # 数据实例6
0x00000001745a6668: 0x00000001745a6670 # “s”字符串对象地址
0x00000001745a6670: 0x0000000000000001
0x00000001745a6678: 0x00000001a38b5058
0x00000001745a6680: 0x00000001745a6690
# mark的验证
t对象处理于无状态,又走不压缩格式,其mark对应是格式应该是
unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
4926097b转为10进制就是1227229563,和我们输入的t.hashCode对应
#intanceKlass验证
class mm.MyTest
mm/MyTest @0x00000001a3cad5f8
#保用class命令找到类的结果和我们的一样。。
#结合的例子<成员>中查看field信息得到offset
#实例对象地址加offset就得到成员数据信息
# 其中静态变量的数据不存在实例中,而在类对象中
# 类对象地址(_java_mirror)加offset就得到静态成员数据信息
oop Klass::_java_mirror: Oop for java/lang/Class @ 0x00000001745a57e8
- 数组对象
# 因为数组gg对象用class的方式找不到,可以通过运行时的本地变量找过去
# 保使用thread <main进程ID> 查看main进程stack,Stack in use by Java,再根据mem命令去
# 或者 直接用ui提供的 stack for memory for main(推荐使用,右边有直接内存值说明)
# 在2是你查以很快找到内容说明为ObjArray的字样找到其地址
mem 0x00000001745a6930 5
0x00000001745a6930: 0x0000000000000001 #mark
0x00000001745a6938: 0x00000001a3cae208 #对应的[Lmm.MyTest
0x00000001745a6940: 0x0000000000000002 #数据长度
0x00000001745a6948: 0x00000001745a6648 #第一mm.MyTest的指针
0x00000001745a6950: 0x0000000000000000 #第二个为null
- 类名,父类,接口
#查看类名
inspect 0x00000001a3cad5f8
Symbol* Klass::_name: Symbol @ 0x00007faa92e00040
mem 0x00007faa92e00040 3
0x00007faa92e00040: 0x08e1dfb100020009
0x00007faa92e00048: 0x736554794d2f6d6d
0x00007faa92e00050: 0x00746e6500000074
Symbol(继承自MetaspaceObj){
unsigned short _length // 16bits,名字长度,这里是0009
volatile short _refcount, // 16bits,0002
int _identity_hash; // 32bits,08e1dfb1
//具体类名,长度为0009*2,为74736554794d2f6d6d,
jbyte _body[1];
}
#使用以这代码
private static String hexToAscii(String hexStr) {
StringBuilder output = new StringBuilder("");
for (int i = 0; i < hexStr.length(); i += 2) {
String str = hexStr.substring(i, i + 2);
output.append((char) Integer.parseInt(str, 16));
}
return output.toString();
}
#得tseTyM/mm
#查看父类
Klass* Klass::_super: Klass @ 0x00000001a3cad3b8
#用同上方法查看名字为:ssalCesaB/mm
#查看接口
Array<Klass*>* InstanceKlass::_local_interfaces: Array<Klass*> @ 0x00000001a3cac420
#用同上方法查看名字为:A/mm
- 成员
#获取其中field信息
Array<u2>* InstanceKlass::_fields: Array<u2> @ 0x00000001a3cac7a0
mem 0x00000001a3cac7a0 6 #查看内存对应的信息
# 最前面4个字节为Array的头信息
# 6*2字节为一组
#[access, name index, sig index, initial value index, low_offset, high_offset]
# offset = int(high_offset,low_offset) >> 2
0x00000001a3cac7a0: 0x001d000900000012#00000012为头信息
0x00000001a3cac7a8: 0x000002810000001e#offset=160,name=001d
0x00000001a3cac7b0: 0x00000020001f0002
0x00000001a3cac7b8: 0x0021000200000061#offset=24,name=001f
0x00000001a3cac7c0: 0x000000810000001e#offset=32,name=0021
0x00000001a3cac7c8: 0x0000000000000000
#结合的例子<常量池>得
001d=TXT
001f=a
0021=s
- 常量池
#获取其中_constants信息
ConstantPool* InstanceKlass::_constants: ConstantPool @ 0x00000001a3cac098
class ConstantPool(继承自MetaspaceObj){
// the tag array describing the constant pool's contents
//常量池数据标记Constant Type
Array<u1>* _tags;
// the cache holding interpreter runtime information
//运行时缓存
ConstantPoolCache* _cache;
// the corresponding class
//哪个类的常量池
InstanceKlass* _pool_holder;
//for variable-sized (InvokeDynamic) nodes, usually empty
//常量池的值 Constant Value
Array<u2>* _operands;
// Array of resolved objects from the constant pool and map from resolved
// object index to original constant pool index
//已经解析过的引用
jobject _resolved_references;
Array<u2>* _reference_map;
#打印常量池
print 0x00000001a3cac098
Holder Class
public class mm.MyTest @0x00000001a3cad5f8
Constants
Index Constant Type Constant Value
1 JVM_CONSTANT_Class public final class java.lang.StringBuilder @0x00000001a3936e90
2 JVM_CONSTANT_Methodref #1 #58
3 JVM_CONSTANT_Fieldref #11 #59
4 JVM_CONSTANT_Methodref #1 #60
5 JVM_CONSTANT_String "@bbb"
6 JVM_CONSTANT_Methodref #1 #62
7 JVM_CONSTANT_Methodref #27 #63
8 JVM_CONSTANT_Fieldref #11 #64
9 JVM_CONSTANT_String "test"
...
20 JVM_CONSTANT_UnresolvedClass mm/B
21 JVM_CONSTANT_String "khkh"
22 JVM_CONSTANT_Methodref #75 #81
23 JVM_CONSTANT_Methodref #11 #82
24 JVM_CONSTANT_String "end"
25 JVM_CONSTANT_Methodref #27 #70
26 JVM_CONSTANT_String "yoyo"
27 JVM_CONSTANT_Class class mm.BaseClass @0x00000001a3cad3b8
28 JVM_CONSTANT_UnresolvedClass mm/A
29 JVM_CONSTANT_Utf8 "TXT"
30 JVM_CONSTANT_Utf8 "Ljava/lang/String;"
31 JVM_CONSTANT_Utf8 "a"
32 JVM_CONSTANT_Utf8 "I"
33 JVM_CONSTANT_Utf8 "s"
...
#结合的例子<成员>得
001d=29=TXT
001f=31=a
0021=33=s
- 方法
#查看类方法
Array<Method*>* InstanceKlass::_methods: Array<Method*> @ 0x00000001a3cac7d0
#Array头对象信息占8字节,我们直接
mem 0x00000001a3cac7d8 6
0x00000001a3cac7d8: 0x00000001a3cac920 #<init>
0x00000001a3cac7e0: 0x00000001a3cacc08 #<clinit>
0x00000001a3cac7e8: 0x00000001a3caca28 #main()
0x00000001a3cac7f0: 0x00000001a3cacb70 #showB()
0x00000001a3cac7f8: 0x00000001a3cacad0 #showA()
0x00000001a3cac800: 0x00000001a3cac858 #getTXT
#打印showA方法
print 0x00000001a3cacad0
public void showA() @0x00000001a3cacad0
Holder Class
public class mm.MyTest @0x00000001a3cad5f8
Bytecode
line bci bytecode
60 0 getstatic #15 [Field java.io.PrintStream out] of public final class java.lang.System @0x00000001a38c95d8
60 3 aload_0
60 4 getfield #8 [Field int a] [fast_igetfield] of public class mm.MyTest @0x00000001a3cad5f8
60 7 invokevirtual #19 [Method void println(int)] of public class java.io.PrintStream @0x00000001a3a1fbd0
61 10 return
#Methnd的结构(继承自MetaspaceObj)
// |------------------------------------------------------|
// | header |
// | klass |
// |------------------------------------------------------|
// | ConstMethod* (oop) |
// |------------------------------------------------------|
// | methodData (oop) |
// | methodCounters |
// |------------------------------------------------------|
// | access_flags |
// | vtable_index |
// |------------------------------------------------------|
// | result_index (C++ interpreter only) |
// |------------------------------------------------------|
// | method_size | intrinsic_id| flags |
// |------------------------------------------------------|
// | code (pointer) |
// | i2i (pointer) |
// | adapter (pointer) |
// | from_compiled_entry (pointer) |
// | from_interpreted_entry (pointer) |
// |------------------------------------------------------|
// | native_function (present only if native) |
// | signature_handler (present only if native) |
// |------------------------------------------------------|
主要参考
《hotspot实战》
《Hotspot Oop模型——Java对象内存表示机制》
《Hotspot Klass模型——Java类内存表示机制》
来源:CSDN
作者:懒猫gg
链接:https://blog.csdn.net/y3over/article/details/103969311