對象的內(nèi)存布局
????????在HotSpot虛擬機中,對象在內(nèi)存中存儲的布局可以分為三塊區(qū)域:對象頭、實例數(shù)據(jù)、對齊填充。
對象頭
????HotSpot虛擬機中的對象頭包括兩部分內(nèi)容: ?
?????????第一部分用于存儲對象自身的運行時數(shù)據(jù),如哈希碼、GC分代年齡、鎖標(biāo)識狀態(tài)、線程持有的鎖、偏向線程ID、偏向時間戳等,因為對象的運行時數(shù)據(jù)很多,所以存儲的結(jié)構(gòu)并不固定。
??????????第二部分是類型指針,即對象執(zhí)行她類元數(shù)據(jù)的指針,虛擬機通過這個指針來確定對象屬于哪個類的實例。(并不是所有的虛擬機實現(xiàn)都必須在對象數(shù)據(jù)上保留類型指針,換句話說,查找對象的類元數(shù)據(jù)并不一定通過對象本身)。如果對象是一個數(shù)組,那么在對象頭中還要存儲數(shù)組的長度。
實例數(shù)據(jù)
????????實例數(shù)據(jù)部分是對象真正儲存的有效信息,也就是在程序代碼中所定義的各種類型的字段內(nèi)容,無論是從父類繼承來的,還是在子類定義的,都需要記錄起來。存儲順序受虛擬機分配策略參數(shù)所影響,HotSpot虛擬機默認(rèn)的分配策略為longs/doubles、ints、shorts/chars、bytes/booleans、ops,從分配策略可以看出,相同寬度的字段總是在一起,在滿足這個條件的情況下,父類中定義的元素會出現(xiàn)在子類之前
對齊填充
????????第三部分的對齊填充數(shù)據(jù)不是必須出現(xiàn)的,也沒有特別的含義,他僅僅起著占位符的作用(由于Hotspot VM的自動內(nèi)存管理喜用要求對象的起始地址必須是8字節(jié)的整數(shù)倍,就是對象的大小不惜是8字節(jié)的整數(shù)倍,所以就需要對齊填充數(shù)據(jù)了)
關(guān)于對象大小的計算
引用自?點我
32 位系統(tǒng)下,當(dāng)使用 new Object() 時,JVM 將會分配 8(Mark Word+類型指針) 字節(jié)的空間,128 個 Object 對象將占用 1KB 的空間。如果是 new Integer(),那么對象里還有一個 int 值,其占用 4 字節(jié),這個對象也就是 8+4=12 字節(jié),對齊后,該對象就是 16 字節(jié)。以上只是一些簡單的對象,那么對象的內(nèi)部屬性是怎么排布的?
Class A {
int i; ?byte b; ? ? ? String str; }
其中對象頭部占用 ‘Mark Word’4 + ‘類型指針’4 = 8 字節(jié);byte 8 位長,占用 1 字節(jié);int 32 位長,占用 4 字節(jié);String 只有引用,占用 4 字節(jié);那么對象 A 一共占用了 8+1+4+4=17 字節(jié),按照 8 字節(jié)對齊原則,對象大小也就是 24 字節(jié)。這個計算看起來是沒有問題的,對象的大小也確實是 24 字節(jié),但是對齊(padding)的位置并不對:在 HotSpot VM 中,對象排布時,間隙是在 4 字節(jié)基礎(chǔ)上的(在 32 位和 64 位壓縮模式下),上述例子中,int 后面的 byte,空隙只剩下 3 字節(jié),接下來的 String 對象引用需要 4 字節(jié)來存放,因此 byte 和對象引用之間就會有 3 字節(jié)對齊,對象引用排布后,最后會有 4 字節(jié)對齊,因此結(jié)果上依然是 7 字節(jié)對齊, 此時對象的結(jié)構(gòu)示意圖,如下圖所示:

對象的訪問定位
????????我們的java程序需要通過棧上的reference數(shù)據(jù)來操作堆上的具體對象,而對象的訪問方式由虛擬機實現(xiàn)來決定,目前主流的訪問方式有句柄和直接指針兩種。
句柄
? ? ? ? 使用句柄的方式,java堆中將會劃分出一塊內(nèi)存來作為句柄池,reference中存儲的就是對象的句柄池地址,而句柄池中包含了對象實例數(shù)據(jù)與類型數(shù)據(jù)各自的具體地址信息。

直接指針
? ? ? ? 使用直接指針訪問,reference存儲的就是對象的地址,而java堆中的對象不僅保存中對象的實例數(shù)據(jù),還引用了對象的類型數(shù)據(jù)。

兩種方式各有優(yōu)勢:
? ? 1。句柄的方式最大的好處就是存儲的是句柄的地址,當(dāng)對象移動時不需要改變引用地址(垃圾回收時對象移動是很頻繁的事情),只改變句柄中實例數(shù)據(jù)的指針,但這需要頻繁的移動指針。
? ? 2.直接指針的方式最大的好處就是速度更快,她節(jié)省了一次指針定位的時間開銷,由于對象的訪問很頻繁的事情,積少成多也可以節(jié)約許多時間成本。
而對于虛擬機sun Hotspot而言,他使用的是直接指針的方式來進行對象訪問的。
一篇關(guān)于JVM內(nèi)存分配模型的概念講的很好的文章:內(nèi)存模型
當(dāng)它本可進取時,卻故作謙卑;
當(dāng)它在空虛時,用愛欲來填充;
在困難和容易之間,它選擇了容易;
它犯了錯,卻借由別人也會犯錯來寬慰自己;
它自由軟弱,卻把它認(rèn)為是生命的堅韌;
當(dāng)它鄙夷一張丑惡的嘴臉時,卻不知那正是自己面具中的一副;
它側(cè)身于生活的污泥中,雖不甘心,卻又畏首畏尾。