java 對象的內存佈局

環境: 本機爲64位操做系統。jdk 1.8數組

1、對象在內存中存儲的佈局能夠分爲3塊區域:對象頭(Header),實例數據(Instance Data),對齊填充(Padding)。ruby

2、咱們能夠經過maven工程引用對應的 jol-core jar包。將對應的內存分佈打印出來作相應的研究。架構

      我這裏寫勒一個類:User,4個字段 佔用 4*4 byte =16 byte 共16字節 (實例數據佔用16字節)併發

  

        ObjectHeader類的打印對象的總體分佈:主要代碼以下:jvm

        System.out.println(ClassLayout.parseInstance(user).instanceSize());maven

        System.out.println(ClassLayout.parseInstance(user).toPrintable());ide

產生結果:oop

上圖中:能夠看到,對象在內存中分爲3塊區域。 對齊填充 在JVM中定義爲 8byte 的 整數倍。 因此 28 % 8 =4 因此須要padding 4 byte 。佈局

Header包含以下內容:主要由 Mark World (8byte)+ Class Pointer (4byte) (類型指針)優化

1. Mark World  根據  對象 lock 標記的狀態不一樣 , 所存儲的內容也會發生改變. 具體以下圖.


|------------------------------------------------------------------------------|--------------------|
|                                  Mark Word (64 bits)                         |       State        |
|------------------------------------------------------------------------------|--------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |       Normal       |
|------------------------------------------------------------------------------|--------------------|
| thread:54 |       epoch:2        | unused:1 | age:4 | biased_lock:1 | lock:2 |       Biased       |
|------------------------------------------------------------------------------|--------------------|
|                       ptr_to_lock_record:62                         | lock:2 | Lightweight Locked |
|------------------------------------------------------------------------------|--------------------|
|                     ptr_to_heavyweight_monitor:62                   | lock:2 | Heavyweight Locked |
|------------------------------------------------------------------------------|--------------------|
|                                                                     | lock:2 |    Marked for GC   |
|------------------------------------------------------------------------------|--------------------|
biased_lock lock 狀態
0 01 無鎖
1 01 偏向鎖
0 00 輕量級鎖
0 10 重量級鎖
0 11 GC標記

lock:2位的鎖狀態標記位,因爲但願用盡量少的二進制位表示儘量多的信息,因此設置了lock標記。該標記的值不一樣,整個mark word表示的含義不一樣。 biased_lock:對象是否啓用偏向鎖標記,只佔1個二進制位。爲1時表示對象啓用偏向鎖,爲0時表示對象沒有偏向鎖。
age:4位的Java對象年齡。在GC中,若是對象在Survivor區複製一次,年齡增長1。當對象達到設定的閾值時,將會晉升到老年代。默認狀況下,並行GC的年齡閾值爲15,併發GC的年齡閾值爲6。因爲age只有4位,因此最大值爲15,這就是-XX:MaxTenuringThreshold選項最大值爲15的緣由。
identity_hashcode:25位的對象標識Hash碼,採用延遲加載技術。調用方法System.identityHashCode()計算,並會將結果寫到該對象頭中。當對象被鎖定時,該值會移動到管程Monitor中。
thread:持有偏向鎖的線程ID。
epoch:偏向時間戳。
ptr_to_lock_record:指向棧中鎖記錄的指針。
ptr_to_heavyweight_monitor:指向管程Monitor的指針。

2. Class Pointer (類型指針) 這一部分用於存儲對象的類型指針,該指針指向它的類元數據,JVM經過這個指針肯定對象是哪一個類的實例。該指針的位長度爲JVM的一個字大小,即32位的JVM爲32位,64位的JVM爲64位。
若是應用的對象過多,使用64位的指針將浪費大量內存,統計而言,64位的JVM將會比32位的JVM多耗費50%的內存。爲了節約內存能夠使用選項+UseCompressedOops開啓指針壓縮,其中,oop即ordinary object pointer普通對象指針。開啓該選項後,下列指針將壓縮至32位:

  1. 每一個Class的屬性指針(即靜態變量)
  2. 每一個對象的屬性指針(即對象變量)
  3. 普通對象數組的每一個元素指針

 上例證:

禁用指針壓縮: -XX:-UseCompressedOops

開啓指針壓縮,jvm默認開啓

固然,也不是全部的指針都會壓縮,一些特殊類型的指針JVM不會優化,好比指向PermGen的Class對象指針(JDK8中指向元空間的Class對象指針)、本地變量、堆棧元素、入參、返回值和NULL指針等。

3. 若是對象是一個數組,那麼對象頭還須要有額外的空間用於存儲數組的長度,這部分數據的長度也隨着JVM架構的不一樣而不一樣:32位的JVM上,長度爲32位;64位JVM則爲64位。64位JVM若是開啓+UseCompressedOops選項,該區域長度也將由64位壓縮至32位

相關文章
相關標籤/搜索