Java對象的存儲佈局以及鎖狀態鎖升級過程

 

Java對象在內存中的結構(非數組)
對象頭 markword(32位JVM佔32位,64位JVM佔64位)
class pointer(32位JVM佔32位,64位JVM在未開起壓縮指針時佔64位,開啓時佔32位):object.Class(如String.Class)
如果是數組,這裏存數組長度(數組長度佔32位),如果不是,則沒有這部分
instance data 對象屬性(以實際對象內屬性爲準)
padding java內存地址按照8bytes對齊,長度必須是8的倍數

 

markword 以及鎖升級過程(32位JVM)
鎖狀態 25bit 4bit 1bit 2bit
23bit 2bit 是否偏向鎖 鎖標誌位
無鎖狀態 對象的hashCode 分代年齡 0 01
偏向鎖 線程id Epoch 分代年齡 1 01
輕量級鎖 指向棧中鎖記錄的指針 00
重量級鎖 指向重量級鎖的指針 10
GC標記 11

無鎖狀態:前25位存的是對象的hashcode--identity hashCode,26--29 位存的是分代年齡(最大分分代年齡2^4 -1 =15),第30位存儲偏向鎖標誌,第31-32位存儲的是鎖標誌位; 

1、一個對象剛剛new出來的時候處於無鎖狀態,鎖標誌位爲:01 ,偏向鎖標誌爲: 0 ,|| identity hashCode || GC age || 0 || 01 ||;

2、當第一個線程鎖定該對象時,會檢查 鎖標誌位 是否是01 ,然後檢查 偏向鎖標誌位是否爲 0,CAS設置線程ID和偏向鎖標誌位,會進入偏向鎖狀態:|| 線程ID || Epoch || GC age || 1 || 01 ||  ,偏向鎖不是併發,線程重複加鎖,由於是偏向於這個線程的,markword記錄線程ID和當前線程ID一樣,所以直接獲得偏向鎖;

3、偏向鎖被爭用的時候回升級爲輕量級鎖,當第二個線程試圖鎖定該對象時,會發生爭搶,鎖狀態升級爲輕量級鎖,輕量級鎖實現原理:當線程爭用這個鎖的時候,會在線程的棧裏面建立一個鎖記錄-LockRecord ,原來的markword (包括hashCode)數據全部複製到了這個LockRecord中,原來的 || 線程ID || Epoch || GC age ||  會被替換成指針,指向這個LockRecord ,然後得到這把偏向鎖,過程:

|| 線程ID || Epoch || GC age || 1 || 01 || --> stack上建立LockRecord --> copy markword 到 LockRecord --> CAS 替換 markword 的lockRecod指針 --> || LockRecord Pointer || 01 ||;

4、輕量級鎖升級爲重量級鎖:發生自旋超過10次,或者等待線程超過CPU核數的一半;

Object o = new Object();

其中的o 佔4個字節,new Object()在:

32位JVM佔8字節:markword:32位,classpointer:32位,如果沒有實例數據instance,不需要對齊padding ,最小佔用8Byte存儲空間;

64位JVM,markword佔64位 ,class pointer在不開啓壓縮存儲情況下佔64位(開啓佔32位),沒有其他實例屬性時,不需要要對齊,佔16字節,開啓壓縮指針佔12字節,對齊4個字節,所以也是16字節;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章