深入理解多線程(三)—— Java的對象頭
上一篇文章中我們從HotSpot的源碼入手,介紹了Java的對象模型。這一篇文章在上一篇文章的基礎(chǔ)上再來介紹一下Java的對象頭。主要介紹一下對象頭的作用,結(jié)構(gòu)以及他和鎖的關(guān)系。
Java對象模型回顧與勘誤
在上一篇文章中,關(guān)于對象頭的部分描述有誤,我已經(jīng)在我博客的文章中就行修正 。這里再重新表述一下。
每一個(gè)Java類,在被JVM加載的時(shí)候,JVM會給這個(gè)類創(chuàng)建一個(gè)instanceKlass,保存在方法區(qū),用來在JVM層表示該Java類。當(dāng)我們在Java代碼中,使用new創(chuàng)建一個(gè)對象的時(shí)候,JVM會創(chuàng)建一個(gè)instanceOopDesc對象,這個(gè)對象中包含了對象頭以及實(shí)例數(shù)據(jù)。
這里提到的對象頭到底是什么呢?
- class oopDesc {
- friend class VMStructs;
- private:
- volatile markOop _mark;
- union _metadata {
- wideKlassOop _klass;
- narrowOop _compressed_klass;
- } _metadata;
- }
上面代碼中的_mark和_metadata其實(shí)就是對象頭的定義。關(guān)于_metadata之前就介紹過,這里不再贅述。由于這個(gè)專題主要想介紹和JAVA并發(fā)相關(guān)的知識,所以本文展開介紹一下_mark ,即mark word。
對象頭信息是與對象自身定義的數(shù)據(jù)無關(guān)的額外存儲成本,考慮到虛擬機(jī)的空間效率,Mark Word被設(shè)計(jì)成一個(gè)非固定的數(shù)據(jù)結(jié)構(gòu)以便在極小的空間內(nèi)存儲盡量多的信息,它會根據(jù)對象的狀態(tài)復(fù)用自己的存儲空間。
對markword的設(shè)計(jì)方式上,非常像網(wǎng)絡(luò)協(xié)議報(bào)文頭:將mark word劃分為多個(gè)比特位區(qū)間,并在不同的對象狀態(tài)下賦予比特位不同的含義。下圖描述了在32位虛擬機(jī)上,在對象不同狀態(tài)時(shí) mark word各個(gè)比特位區(qū)間的含義。
同樣,在HotSpot的源碼中我們可以找到關(guān)于對象頭對象的定義,會一一印證上圖的描述。對應(yīng)與markOop.hpp類。
- enum { age_bits = 4,
- lock_bits = 2,
- biased_lock_bits = 1,
- max_hash_bits = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
- hash_bits = max_hash_bits > 31 ? 31 : max_hash_bits,
- cms_bits = LP64_ONLY(1) NOT_LP64(0),
- epoch_bits = 2
- };
從上面的枚舉定義中可以看出,對象頭中主要包含了GC分代年齡、鎖狀態(tài)標(biāo)記、哈希碼、epoch等信息。
從上圖中可以看出,對象的狀態(tài)一共有五種,分別是無鎖態(tài)、輕量級鎖、重量級鎖、GC標(biāo)記和偏向鎖。在32位的虛擬機(jī)中有兩個(gè)Bits是用來存儲鎖的標(biāo)記為的,但是我們都知道,兩個(gè)bits最多只能表示四種狀態(tài):00、01、10、11,那么第五種狀態(tài)如何表示呢 ,就要額外依賴1Bit的空間,使用0和1來區(qū)分。
在32位的HotSpot虛擬機(jī) 中對象未被鎖定的狀態(tài)下,Mark Word的32個(gè)Bits空間中的25Bits用于存儲對象哈希碼(HashCode),4Bits用于存儲對象分代年齡,2Bits用于存儲鎖標(biāo)志位,1Bit固定為0,表示非偏向鎖。
markOop.hpp類中有關(guān)于對象狀態(tài)的定義:
- enum { locked_value = 0,
- unlocked_value = 1,
- monitor_value = 2,
- marked_value = 3,
- biased_lock_pattern = 5
- };
簡單翻譯一下:
- locked_value(00) = 0
- unlocked_value(01) = 1
- monitor_value(10) = 2
- marked_value(11) = 3
- biasedlockpattern(101) = 5
關(guān)于為什么要定義這么多狀態(tài),上面提到的輕量級鎖、重量級鎖、偏向鎖以及他們之前的關(guān)系,會在下一篇文章中重點(diǎn)闡述。
【本文是51CTO專欄作者Hollis的原創(chuàng)文章,作者微信公眾號Hollis(ID:hollischuang)】