對象頭 | 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的倍數) |
鎖狀態 | 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字節;