在HotSpot虛擬機中左敌,對象的內(nèi)存布局分為三塊區(qū)域:對象頭(Object Header)饰潜、實例數(shù)據(jù)(Instance Data)绽淘、對齊填充(Padding)。
- 對象頭(Object Header)
- 存儲對象自身的運行時數(shù)據(jù):如HashCode俄周、GC分代年齡、鎖狀態(tài)標志髓迎、線程持有的鎖峦朗、偏向線程ID、偏向時間戳等
這部分數(shù)據(jù)的長度在32位和64位的虛擬機(未開啟壓縮指針)中分別為32bit和64bit排龄,官方稱它為"MarkWord"波势。對象需要存儲的運行時數(shù)據(jù)很多,其實已經(jīng)超出了32位橄维、64位Bitmap結(jié)構(gòu)所能記錄的限度尺铣,但是對象頭信息是與對象自身定義的數(shù)據(jù)無關(guān)的額外存儲成本,考慮到虛擬機的空間效率争舞,MarkWord被設(shè)計成一個非固定的數(shù)據(jù)結(jié)構(gòu)以便在極小的空間內(nèi)存儲盡量多的信息凛忿,它會根據(jù)對象的狀態(tài)復用自己的存儲空間。例如竞川,在32位的HotSpot虛擬機中店溢,如果對象處于未被鎖定的狀態(tài)下,那么MarkWord的32bit空間中的25bit用于存儲對象哈希碼委乌,4bit用于存儲對象分代年齡床牧,2bit用于存儲鎖標志位,1bit固定為0遭贸,而在其他狀態(tài)(輕量級鎖定戈咳、重量級鎖定、GC標記、可偏向)下對象的存儲內(nèi)容見表2-1除秀。
- 類型指針(即對象指向它的類元數(shù)據(jù)的指針):虛擬機通過這個指針來確定這個對象是哪個類的實例糯累。(注:并不是所有虛擬機的實現(xiàn)都必須在對象數(shù)據(jù)里保存類型指針,換句話說册踩,查找對象的類的元數(shù)據(jù)信息不一定要通過對象本身)另外如果對象是一個數(shù)組泳姐,那么在對象頭中還必須有一塊來記錄數(shù)據(jù)的長度,因為虛擬機可以根據(jù)普通對象的元數(shù)據(jù)信息來確定對象的大小暂吉,但是從數(shù)組的元數(shù)據(jù)里無法確定數(shù)組的大小胖秒。
- 存儲對象自身的運行時數(shù)據(jù):如HashCode俄周、GC分代年齡、鎖狀態(tài)標志髓迎、線程持有的鎖峦朗、偏向線程ID、偏向時間戳等
- 實例數(shù)據(jù) (instance Data)
對象真正存儲的有效信息,也是在程序代碼中定義的各種類型的字段內(nèi)容慕的。無論是父類繼承的還是子類中定義的阎肝,都需要記錄起來。
這部分的存儲順序會受到虛擬機分配策略參數(shù)(FieldsAllocationStyle)和字段在Java源碼中定義順序的影響肮街。HotSpot虛擬機默認的分配策略為longs/doubles风题、ints、shorts/chars嫉父、bytes/booleans沛硅、oops(OrdinaryObjectPointers),從分配策略中可以看出绕辖,相同寬度的字段總是被分配到一起摇肌。在滿足這個前提條件的情況下,在父類中定義的變量會出現(xiàn)在子類之前仪际。如果CompactFields參數(shù)值為true(默認為true)围小,那么子類之中較窄的變量也可能會插入到父類變量的空隙之中。
- 對齊填充(Padding)
對齊填充并不是必然存在的树碱,也沒有特別的含義肯适,它僅僅起著占位符的作用。
由于HotSpotVM的自動內(nèi)存管理系統(tǒng)要求對象起始地址必須是8字節(jié)的整數(shù)倍赴恨,換句話說疹娶,就是對象的大小必須是8字節(jié)的整數(shù)倍。而對象頭部分正好是8字節(jié)的倍數(shù)(1倍或者2倍)伦连,因此雨饺,當對象實例數(shù)據(jù)部分沒有對齊時,就需要通過對齊填充來補全惑淳。
相關(guān)文章:
java虛擬機中對象的創(chuàng)建
java虛擬機中對象的內(nèi)存布局
java虛擬機中對象的定位