ART虛擬機 | Java對象和類的內存結構

當咱們經過new建立一個Java對象時,虛擬機會安排內存分配的全部工做。但一個Java對象在內存中到底長什麼樣?它的實例對象放在哪裏?繼承關係如何處理?這些問題對於你們一般是陌生的。本文試圖經過圖表示例的方式,將對象和類的內存結構具象化。java

1. Java對象頭

全部Java類最終的父類都是java.lang.Object,所以當咱們建立一個Java對象時,必然伴隨着java.lang.Object的實例化過程。Java.lang.Object在ART中有個對應的C++類art::mirror::Object,命名空間中有"mirror",表示其和Java類之間存在對應關係。當咱們經過new Object()來建立一個java對象時,就會在內存空間獲得一個最簡單的內存結構。markdown

對象結構.png

該內存結構中只存儲了兩個C++字段:klass_monitor_,分別對應於java.lang.Object中的shadow$_klass_shadow$_monitor_。這8個字節一般又被稱爲對象頭,是全部Java對象都必須分配的空間。spa

如下是一個實際的art::mirror::Object的數據。須要注意的是,kVTableLengthhash_code_seed是art::mirror::Object的靜態字段,不會存在於Java對象中。3d

object示例.png

2. Java類對象(類頭)

Java中提供了一個java.lang.Class類,該類的實例表示一個運行程序中的類或接口。實例中的字段記錄了類或接口的元數據。code

當咱們想要建立一個java.lang.Class類的實例(類對象)時,如下三種方法可供選擇:orm

  1. Class.forName("className")
  2. MyClass.class
  3. obj.getClass()

假設咱們有一個類com.hangl.Example,那麼com.hangl.Example.class就表示該類的類對象。在ART中,該類對象的建立同時也是art::mirror::Class的實例化過程。對象

因爲java.lang.Class繼承於java.lang.Object,所以art::mirror::Class也繼承於art::mirror::Object。因此一個art::mirror::Class對象在內存結構上也包含klass_monitor_字段。繼承

類對象結構.png

如下是一個實際的art::mirror::Class的數據。一樣,kClassWalkSuperkPrimitiveTypeSizeShiftShiftkPrimitiveTypeMask是art::mirror::Class的靜態字段,所以不會存在於Java類對象中。接口

class示例.png

3. Java.lang.Object.class和java.lang.Class.class的關係

Object和Class的關係.png

自定義object和Class的關係.png

4. 實例字段的存儲位置

前文提到,最簡單的Java對象只佔用8字節,裏面存儲了兩個字段:klass_monitor_。這8字節也能夠稱爲對象頭,是每一個對象都必須具有的。內存

大多數對象除了對象頭之外,還須要存儲類的實例字段。每一個類的實例字段大小不一,其大小在Class加載階段中的LinkClass時決定。這些實例字段緊隨着對象頭排列存儲,所以一個對象的真實內存佔用一般以下所示。

複雜對象的內存結構.png

5. 靜態字段的存儲位置

一個類所具備的信息能夠分爲兩部分,一部分是元數據,例如該類有多少個實例字段,多少個虛擬方法等,是描述性的信息。另外一部分則是靜態字段的值。元數據能夠經過art::mirror::Class對象來表示,而靜態字段將緊隨其後。

這種內存結構和Java對象十分類似,上半部分是元數據,下半部分是字段值。只不過對象的元數據是klass_monitor_,而類的元數據是class_loader_methods_等。對象中的字段值是實例字段,類的字段值是靜態字段。

不過須要注意一點,每一個類的靜態字段在內存中都是獨一份,所以子類中不須要存儲父類的靜態字段。這和實例字段是不一樣的。

複雜類的內存結構.png

6. 對象和類的關係

建立對象.png

相關文章
相關標籤/搜索