Java對象在內存的結構

1、內存佈局

對象在內存中存儲的結構由三部分組成:對象頭、實例數據、對齊填充。java


  1. 對象頭

    MarkWord(標記字段):哈希碼、分代年齡、鎖標誌位、偏向線程ID、偏向時間戳等信息。Mark Word被設計成了一個非固定的數據結構以便在極小的空間內存儲儘可能多的信息,它會根據對象的狀態複用本身的存儲空間。例外:若是是數組的話,還須要有一塊區域存放數組大小,由於沒辦法從元數據確認數組大小,因此要存儲到對象頭的MarkWord中。數組

    MarkWord是根據對象的狀態區分不一樣的狀態位,從而區分不一樣的存儲結構。例以下圖:數據結構


    對象頭的另外一部分是類型指針(Klass Pointer)。app

    Klass Pointer(類型指針):即指向當前對象的類的元數據的指針,虛擬機經過這個指針來肯定這個對象是哪一個類的實例。並非全部的虛擬機實現都必須在對象數據上保留類型指針,換句話說查找對象的元數據信息並不必定要通過對象自己。oop

    另外,若是是數組,對象頭中還有一塊用於存放數組長度的數據,由於虛擬機能夠經過普通Java對象的元數據信息肯定Java對象的大小,可是從數組的元數據中沒法肯定數組的大小。其中偏向鎖和輕量級鎖是java6之後對synchronized進行優化後新增的,稍後作介紹。佈局

  2. 實例數據

    實例數據部分是對象真正存儲的有效信息,也就是咱們在程序代碼裏面所定義的各類類型的字段內容,不管是從父類繼承下來的,仍是在子類中定義的都須要記錄下來。 這部分的存儲順序會受到虛擬機分配策略參數(FieldsAllocationStyle)和字段在Java源碼中定義順序的影響。優化

    HotSpot虛擬機 默認的分配策略爲longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),從分配策略中能夠看出,相同寬度的字段老是被分配到一塊兒。在知足這個前提條件的狀況下,在父類中定義的變量會出如今子類以前。若是 CompactFields參數值爲true(默認爲true),那子類之中較窄的變量也可能會插入到父類變量的空隙之中。ui

  3. 對齊填充

    第三部分對齊填充並非必然存在的,也沒有特別的含義,它僅僅起着佔位符的做用。因爲HotSpot VM的自動內存管理系統要求對象起始地址必須是8字節的整數倍,換句話說就是對象的大小必須是8字節的整數倍。對象頭正好是8字節的倍數(1倍或者2倍),所以當對象實例數據部分沒有對齊的話,就須要經過對齊填充來補全。spa

2、建立過程

在語言層面上,建立對象一般(例外:克隆、反序列化)僅僅是一個 new關鍵字而已,而在虛擬機中,對象(限於普通Java對象,不包括數組和Class對象等)的建立又是怎樣的?線程

如下分析虛擬機遇到new指令時的操做:

一個對象的存儲涉及內存的三部分:方法棧(存儲指針)、方法區(存儲類信息、常量、靜態變量)、堆(存儲對象的實例數據)。其中關於最左側圖中「對象的引用」有兩種實現方式,以下右圖(兩種:一、經過句柄實現;二、直接指針實現;):




3、舉例

在Hotspot JVM中,32位機器下,Integer對象的大小是int的幾倍?

int佔用的是4字節。由以上分析可得Integer的結構以下:


Integer只有一個int類型的成員變量value,因此其對象實際數據部分的大小是4個字節,而後再在後面填充4個字節達到8字節的對齊,因此能夠得出Integer對象的大小是16個字節。

所以,咱們能夠得出Integer對象的大小是原生的int類型的4倍。

關於對象的內存結構,須要注意數組的內存結構和普通對象的內存結構稍微不一樣,由於數據有一個長度length字段,因此在對象頭後面還多了一個int類型的length字段,佔4個字節,接下來纔是數組中的數據,以下:

相關文章
相關標籤/搜索