對象的內(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虛擬機默認的分配策略為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)它在空虛時篮绰,用愛欲來填充;
在困難和容易之間季惯,它選擇了容易吠各;
它犯了錯臀突,卻借由別人也會犯錯來寬慰自己;
它自由軟弱走孽,卻把它認為是生命的堅韌惧辈;
當(dāng)它鄙夷一張丑惡的嘴臉時,卻不知那正是自己面具中的一副磕瓷;
它側(cè)身于生活的污泥中,雖不甘心念逞,卻又畏首畏尾困食。