Java对象内存表示机制

前言

在《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------------------**/


案例材料

  1. 实验类
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);
    }
}
  1. 运行结果

6
7
class [Lmm.MyTest;
1227229563
khkh
yoyo@bbb

  1. sa命令

sudo java -cp .:$JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB
Hotspot学习利器:HSDB和CLHSDB

  1. 查看分区情况
universe
ParallelScavengeHeap [ 
	PSYoungGen 
		[ eden = [0x0000000174380000,0x00000001746199d8,0x0000000176400000] ,
		  from = [0x0000000176900000,0x0000000176900000,0x0000000176e00000] , 
		  to =   [0x0000000176400000,0x0000000176400000,0x0000000176900000]  
		] 
	PSOldGen [  [0x000000011ee00000,0x000000011ee00000,0x0000000124380000]  ]  ] 
  1. 在eden中搜索mm.MyTest对象
scanoops 0x0000000174380000 0x0000000176400000 mm.MyTest

0x00000001745a6648 mm/MyTest
  1. 查看对象的具体数据
#因为我在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

  1. 数组对象
# 因为数组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
  1. 类名,父类,接口
#查看类名
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
  1. 成员
#获取其中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

  1. 常量池
#获取其中_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

  1. 方法
#查看类方法
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类内存表示机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值