當咱們經過new建立一個Java對象時,虛擬機會安排內存分配的全部工做。但一個Java對象在內存中到底長什麼樣?它的實例對象放在哪裏?繼承關係如何處理?這些問題對於你們一般是陌生的。本文試圖經過圖表示例的方式,將對象和類的內存結構具象化。java
全部Java類最終的父類都是java.lang.Object,所以當咱們建立一個Java對象時,必然伴隨着java.lang.Object的實例化過程。Java.lang.Object在ART中有個對應的C++類art::mirror::Object,命名空間中有"mirror",表示其和Java類之間存在對應關係。當咱們經過new Object()
來建立一個java對象時,就會在內存空間獲得一個最簡單的內存結構。markdown
該內存結構中只存儲了兩個C++字段:klass_
和monitor_
,分別對應於java.lang.Object中的shadow$_klass_
和shadow$_monitor_
。這8個字節一般又被稱爲對象頭,是全部Java對象都必須分配的空間。spa
如下是一個實際的art::mirror::Object的數據。須要注意的是,kVTableLength
和hash_code_seed
是art::mirror::Object的靜態字段,不會存在於Java對象中。3d
類對象
(類頭)Java中提供了一個java.lang.Class類,該類的實例表示一個運行程序中的類或接口。實例中的字段記錄了類或接口的元數據。code
當咱們想要建立一個java.lang.Class類的實例(類對象)時,如下三種方法可供選擇:orm
假設咱們有一個類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_
字段。繼承
如下是一個實際的art::mirror::Class的數據。一樣,kClassWalkSuper
,kPrimitiveTypeSizeShiftShift
和kPrimitiveTypeMask
是art::mirror::Class的靜態字段,所以不會存在於Java類對象
中。接口
前文提到,最簡單的Java對象只佔用8字節,裏面存儲了兩個字段:klass_
和monitor_
。這8字節也能夠稱爲對象頭,是每一個對象都必須具有的。內存
大多數對象除了對象頭之外,還須要存儲類的實例字段。每一個類的實例字段大小不一,其大小在Class加載階段中的LinkClass時決定。這些實例字段緊隨着對象頭排列存儲,所以一個對象的真實內存佔用一般以下所示。
一個類所具備的信息能夠分爲兩部分,一部分是元數據,例如該類有多少個實例字段,多少個虛擬方法等,是描述性的信息。另外一部分則是靜態字段的值。元數據能夠經過art::mirror::Class對象來表示,而靜態字段將緊隨其後。
這種內存結構和Java對象十分類似,上半部分是元數據,下半部分是字段值。只不過對象的元數據是klass_
和monitor_
,而類的元數據是class_loader_
和methods_
等。對象中的字段值是實例字段,類的字段值是靜態字段。
不過須要注意一點,每一個類的靜態字段在內存中都是獨一份,所以子類中不須要存儲父類的靜態字段。這和實例字段是不一樣的。