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類內存表示機制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章