JVM 對象結構


 

HotSpot虛擬機中,對象在內存中存儲的布局可以分為三塊區域: 對象頭(Header)、 實例數據(Instance Data)和 對齊填充(Padding)
 
1.對象頭
HotSpot虛擬機的對象頭(Object Header)包括兩部分信息,
(1)第一部分 MarkWord:用於存儲對象自身的運行時數據, 如 哈希碼(HashCode)、 GC分代年齡鎖狀態標志線程持有的鎖偏向線程ID偏向時間戳等等,這部分數據的長度在32位和64位的虛擬機(暫 不考慮開啟壓縮指針的場景)中分別為32個和64個Bits,官方稱它為“Mark Word”。
一個類被加載的時候,hashCode是被存放在對象頭里面的Mark Word里面的。
 
(2)第一部分 KlassWord,即 類型指針,即是 對象指向它的類的元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。並不是所有的虛擬機實現都必須在對象數據上保留類型指針,換句話說查找對象的元數據信息並不一定要經過對象本身。另外,如果對象是一個Java數組,那在對象頭中還必須有一塊用於記錄數組長度的數據,因為虛擬機可以通過普通Java對象的元數據信息確定Java對象的大小,但是從數組的元數據中無法確定數組的大小。 
 

 

 

2.實例數據
實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內容。無論是從父類繼承下來的,還是在子類中定義的,都需要記錄起來。
 
3.對齊填充
第三部分對齊填充並不是必然存在的,也沒有特別的含義,它僅僅起着占位符的作用。由於HotSpot VM的自動內存管理系統要求對象起始地址必須是8字節的整數倍,換句話說,就是對象的大小必須是8字節的整數倍。而對象頭部分正好是8字節的倍數(1倍或者2倍),因此,當對象實例數據部分沒有對齊時,就需要通過對齊填充來補全。

 

普通對象和數組類型圖例

  • 對象頭中的Mark Word(標記字)主要用來表示對象的線程鎖狀態,另外還可以用來配合GC、存放該對象的hashCode;
  • Klass Word是一個指向方法區中Class信息的指針,意味着該對象可隨時知道自己是哪個Class的實例;
  • 數組長度也是占用64位(8字節)的空間,這是可選的,只有當本對象是一個數組對象時才會有這個部分;
  • 對象體是用於保存對象屬性和值的主體部分,占用內存空間取決於對象的屬性數量和類型;
  • 對齊字是為了減少堆內存的碎片空間(不一定准確)。
 
所有對象都繼承自oopDesc類:
class oopDesc{
    private:
        volatile markOop _mark; //對象的運行時信息,如hashcode、GC年齡、鎖等
        union _metaData{        //對象的元數據指針,指向描述對象的klass對象
            wideKlassOop _klass;
            narrowOop _compressed_klass;
        }_metaData;
    ......
}

每當調用new創建一個新對象時,都會在堆中分配內存,並創建一個對象實例,其中包含對象頭和實例數據,然后將創建的結果的引用返回給Java棧中的局部變量了。通過對象頭可以訪問對象的運行時信息(_mark )和對象類型相關信息( _metaData指針 )了。

 

HotSpot中對象訪問采用直接指針的方式實現,如下圖所示: 

Java程序是通過Java棧中的reference引用來操作堆上的具體對象的:  
1)當要訪問實例數據即類中的一般屬性時,可通過reference直接訪問堆中對象的實例數據  
2)當要訪問對象的方法和靜態屬性時,則通過_metaData指針訪問方法區的klass對象即可  
3)由於klass對象中含有虛函數表vtbl,因此每個對象通過_metaData指針訪問klass對象便可以找到所有的虛函數  
4)klass含有_super、_subclass等信息,因此可以找到每個類的所有父類、子類、兄弟類等

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM