Java物件模型

來源:互聯網
上載者:User

標籤:point   type   TE   rgs   blank   main   ros   設計者   obj   

java對象

在記憶體中,一個Java對象包含三部分:對象頭、執行個體資料和對齊填充。而對象頭中又包含鎖狀態標誌、線程持有的鎖等標誌。

oop-klass model

OOP(Ordinary Object Pointer)指的是普通對象指標,而Klass用來描述對象執行個體的具體類型。

oop體系:

//定義了oops共同基類typedef class   oopDesc*                            oop;//表示一個Java類型執行個體typedef class   instanceOopDesc*            instanceOop;//表示一個Java方法typedef class   methodOopDesc*                    methodOop;//表示一個Java方法中的不變資訊typedef class   constMethodOopDesc*            constMethodOop;//記錄效能資訊的資料結構typedef class   methodDataOopDesc*            methodDataOop;//定義了數組OOPS的抽象基類typedef class   arrayOopDesc*                    arrayOop;//表示持有一個OOPS數組typedef class   objArrayOopDesc*            objArrayOop;//表示容納基本類型的數組typedef class   typeArrayOopDesc*            typeArrayOop;//表示在Class檔案中描述的常量池typedef class   constantPoolOopDesc*            constantPoolOop;//常量池告訴緩衝typedef class   constantPoolCacheOopDesc*   constantPoolCacheOop;//描述一個與Java類對等的C++類typedef class   klassOopDesc*                    klassOop;//表示對象頭typedef class   markOopDesc*                    markOop;

 如上面代碼所示, oops模組包含多個子模組, 每個子模組對應一個類型, 每一個類型的oop都代表一個在JVM內部使用的特定對象的類型。其中有一個變數oop的類型oopDesc是oops模組的共同基底類型。而oopDesc類型又包含instanceOopDesc (類執行個體)、arrayOopDesc (數組)等子類類型。其中instanceOopDesc 中主要包含以下幾部分資料:markOop _mark和union _metadata 以及一些不同類型的 field。

在java程式運行過程中, 每建立一個新的java對象, 在JVM內部就會相應的建立一個對應類型的oop對象來表示該java對象。而在HotSpot虛擬機器中, 對象在記憶體中包含三塊地區: 對象頭、執行個體資料和對齊填充。其中對象頭包含兩部分內容:_mark和_metadata,而執行個體資料則儲存在oopDesc中定義的各種field中。

_mark:

_mark這一部分用於儲存物件自身的運行時資料, 如雜湊碼、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳記等, 這部分資料的長度在32位和64位的虛擬機器(未開啟壓縮指標)中分別為32bit和64bit, 官方稱它為 "Mark Word"。對象需要儲存的運行時資料很多, 其實已經超出了32位和64位Bitmap結構所能記錄的限度, 但是對象頭資訊是與對象自身定義的資料無關的額外儲存成本, 考慮到虛擬機器的空間效率, Mark Word被設計成一個非固定的資料結構以便在極小的空間記憶體儲盡量多的資訊, 它會根據對象的狀態複用自己的儲存空間。  

_metadata:

_metadata這一部分是類型指標, 即對象指向它的類別中繼資料的指標, 虛擬機器通過這個指標來確定這個對象是哪個類的執行個體。並不是所有的虛擬機器實現都必須在對象資料上保留類型指標, 換句話說尋找對象的中繼資料資訊並不一定要經過對象本身, 其取決於虛擬機器實現的對象訪問方式。目前主流的訪問方式有使用控制代碼和直接指標兩種, 兩者方式的不同這裡先暫不做介紹。另外, 如果對象是一個Java數組, 那麼在對象頭中還必須有一塊用於記錄數組長度的資料, 因為虛擬機器可以通過普通java對象的中繼資料資訊確定java對象的大小, 但是從數組的中繼資料中卻無法確定數組的大小。  

klass

Klass體系:

//klassOop的一部分,用來描述語言層的類型class  Klass;//在虛擬機器層面描述一個Java類class   instanceKlass;//專有instantKlass,表示java.lang.Class的Klassclass     instanceMirrorKlass;//專有instantKlass,表示java.lang.ref.Reference的子類的Klassclass     instanceRefKlass;//表示methodOop的Klassclass   methodKlass;//表示constMethodOop的Klassclass   constMethodKlass;//表示methodDataOop的Klassclass   methodDataKlass;//作為klass鏈的端點,klassKlass的Klass就是它自身class   klassKlass;//表示instanceKlass的Klassclass     instanceKlassKlass;//表示arrayKlass的Klassclass     arrayKlassKlass;//表示objArrayKlass的Klassclass       objArrayKlassKlass;//表示typeArrayKlass的Klassclass       typeArrayKlassKlass;//表示array類型的抽象基類class   arrayKlass;//表示objArrayOop的Klassclass     objArrayKlass;//表示typeArrayOop的Klassclass     typeArrayKlass;//表示constantPoolOop的Klassclass   constantPoolKlass;//表示constantPoolCacheOop的Klassclass   constantPoolCacheKlass;

和oopDesc是其他oop類型的父類一樣,Klass類是其他klass類型的父類。

Klass向JVM提供兩個功能:

  • 實現語言層面的Java類(在Klass基類中已經實現)
  • 實現Java對象的分發功能(由Klass的子類提供虛函數實現)

HotSpot JVM的設計者因為不想讓每一個對象中都含有一個虛函數表, 所以設計了oop-klass模型, 將對象一分為二, 分為klass和oop。其中oop主要用於表示對象的執行個體資料, 所以不含有任何虛函數。而klass為了實現虛函數多態, 所以提供了虛函數表。所以,關於Java的多態,其實也有c++虛函數的影子在。

InstanceClass

JVM在運行時,需要一種用來標識Java內部類型的機制。在HotSpot中的解決方案是:為每一個已載入的Java類建立一個InstanceClass對象,用來在JVM層表示Java類。

InstanceClass內部結構:

//類擁有的方法列表  objArrayOop     _methods;  //描述方法順序  typeArrayOop    _method_ordering;  //實現的介面  objArrayOop     _local_interfaces;  //繼承的介面  objArrayOop     _transitive_interfaces;  //域  typeArrayOop    _fields;  //常量  constantPoolOop _constants;  //類載入器  oop             _class_loader;  //protected域  oop             _protection_domain;      ....

在JVM中,對象在記憶體中的基本存在形式就是oop。那麼,對象所屬的類,在JVM中也是一種對象,因此它們實際上也會被組織成一種oop,即klassOop。同樣的,對於klassOop,也有對應的一個klass來描述,它就是klassKlass,也是klass的一個子類。klassKlass作為oop的klass鏈的端點, 它的klass就是它自身。

記憶體儲存

我們首先來看看下面這段代碼的儲存結構。

class Model{    public static int a = 1;    public int b;    public Model(int b) {        this.b = b;    }}public static void main(String[] args) {    int c = 10;    Model modelA = new Model(2);    Model modelB = new Model(3);}

儲存結構如下:

由此我們能得出結論: 對象的執行個體(instantOopDesc)儲存在堆上,對象的中繼資料(instantKlass)儲存在方法區,對象的引用儲存在棧上。

小結

在JVM載入java類的時候, JVM會給這個類建立一個instanceKlass並儲存在方法區, 用來在JVM層表示該java類。當我們使用new關鍵字建立一個對象時, JVM會建立一個instanceOopDesc對象, 這個對象包含了對象頭和中繼資料兩部分資訊。對象頭中有一些運行時資料, 其中就包括和多線程有關的鎖的資訊。而中繼資料維護的則是指向對象所屬的類的InstanceKlass的指標。

參考資料

深入理解多線程(二)—— Java的物件模型-HollisChuang‘s Blog

深入理解多線程(三)—— Java的對象頭-HollisChuang‘s Blog

Java物件模型

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.