jvm系列java
本文主要簡述Java對象的內存佈局以及其大小的計算。
在HotSpot虛擬機中,對象在內存中存儲的佈局能夠分爲3塊區域:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。
HotSpot虛擬機的對象頭包括兩部分信息:
第一部分markword,用於存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分數據的長度在32位和64位的虛擬機(未開啓壓縮指針)中分別爲32bit和64bit,官方稱它爲「MarkWord」。
對象頭的另一部分是klass,類型指針,即對象指向它的類元數據的指針,虛擬機經過這個指針來肯定這個對象是哪一個類的實例.
實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各類類型的字段內容。不管是從父類繼承下來的,仍是在子類中定義的,都須要記錄起來。
第三部分對齊填充並非必然存在的,也沒有特別的含義,它僅僅起着佔位符的做用。因爲HotSpot VM的自動內存管理系統要求對象起始地址必須是8字節的整數倍,換句話說,就是對象的大小必須是8字節的整數倍。而對象頭部分正好是8字節的倍數(1倍或者2倍),所以,當對象實例數據部分沒有對齊時,就須要經過對齊填充來補全。
在32位系統下,存放Class指針的空間大小是4字節,MarkWord是4字節,對象頭爲8字節。
在64位系統下,存放Class指針的空間大小是8字節,MarkWord是8字節,對象頭爲16字節。
64位開啓指針壓縮的狀況下,存放Class指針的空間大小是4字節,MarkWord是8字節,對象頭爲12字節。
數組長度4字節+數組對象頭8字節(對象引用4字節(未開啓指針壓縮的64位爲8字節)+數組markword爲4字節(64位未開啓指針壓縮的爲8字節)
)+對齊4=16字節。
靜態屬性不算在對象大小內。
import java.util.HashMap; /** * 64位開啓指針壓縮的話,markword變成8字節,壓縮了class指針爲4字節,故對象頭12字節 * 64位沒有開啓指針壓縮的話,markword8字節,class指針8字節,對象頭16字節 * 32位markword爲4字節,class指針爲4字節,對象頭8字節 * * 另外,靜態屬性所佔用的空間一般不算在對象自己,由於它的引用是在方法區。 * * @author xixicat * @created 2014-10-03 */ public class ObjectSize { public static void main(String[] args){ System.out.println(SizeOfTool.getObjectSize(new A(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new B(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new C(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new D(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new E(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new Q(),SizeEnum.B)); /** * 64位壓縮指針下,對象頭12字節,數組長度描述4字節,數據4*100 =16+400 = 416 */ System.out.println(SizeOfTool.getObjectSize(new int[100],SizeEnum.B)); /** * 屬性4位對齊 * 64位壓縮指針下,對象頭12字節,數組長度描述4字節,數據1*100,對齊後104 = 16+104 = 120 */ System.out.println(SizeOfTool.getObjectSize(new byte[100],SizeEnum.B)); /** * 二維數組 * 64位指針壓縮下 * 第1維數組,對象頭12字節,數組長度描述4字節,2個數組引用共8字節,共24字節 * 第2維數組,對象頭12字節,數組長度描述4字節,100個數組引用共400字節,對齊後共416字節 * 第1維的2個引用所指對象大小 = 2*416 = 832 字節 * 共24+832 = 856字節 */ System.out.println(SizeOfTool.getObjectSize(new int[2][100],SizeEnum.B)); /** * 二維數組 * 64位指針壓縮下 * 第1維數組,對象頭12字節,數組長度描述4字節,100個數組引用共400字節,共416字節 * 第2維數組,對象頭12字節,數組長度描述4字節,2個數組引用共8字節,共24字節 * 第1維的100個引用所指對象大小 = 100*24 = 2400 字節 * 共416+2400 = 2816字節 */ System.out.println(SizeOfTool.getObjectSize(new int[100][2],SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new Object(),SizeEnum.B)); /** * 不算static屬性 * private final char value[]; * private int hash; // Default to 0 * private transient int hash32 = 0; * * 32位下,String對象頭8字節,2個int類型8字節,char數組引用佔4字節,共佔24字節 * 另外,還要算上value[]數組的佔用,數組對象頭部8字節,數組長度4字節,對齊後共佔16字節 * =》String對象對象大小24+16 = 40字節 * 64位開啓指針壓縮下(壓縮指針),String對象頭12字節,2個int類型8字節,char數組引用佔4字節,共佔24字節 * 另外,還要算上value[]數組的佔用,數組對象頭部12字節,數組長度4字節,對齊後共佔16字節 * =》String對象大小24+16=40字節 */ System.out.println(SizeOfTool.getObjectSize(new String(),SizeEnum.B)); /** * transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; * transient int size; * int threshold; * final float loadFactor; * transient int modCount; * * 64位開啓指針壓縮下,對象頭部12字節,數組引用4字節,3個int12字節,float4字節,共32字節 * 另外,算上Entry<K,V>[] = 對象頭12 +屬性16字節+數組長度4字節 = 32字節 * * final K key; * V value; * Entry<K,V> next; * int hash; * * 對象頭12字節,3個引用共12字節,1個int4字節 =》 一個entry至少佔用28字節 * * =》32+32=64字節 */ System.out.println(SizeOfTool.getObjectSize(new HashMap(),SizeEnum.B)); } } //32位下對象頭8字節,byte佔1字節,對其填充後,總佔16字節 //64位開啓指針壓縮下對象頭12字節,byte1字節,對齊後佔16字節 class A{ byte b1; } //32位下對象頭8字節,8個byte8字節,總16字節 //64位開啓指針壓縮下對象頭12字節,8個byte8字節,對齊後佔24字節 class B{ byte b1,b2,b3,b4,b5,b6,b7,b8; } //32位下對象頭8字節,9個byte9字節,對其填充後,總24字節 //64位開啓指針壓縮下對象頭12字節,9個byte9字節,對齊後佔24字節 class C{ byte b1,b2,b3,b4,b5,b6,b7,b8,b9; } //32位下對象頭8字節,int佔4字節,引用佔4字節,共16字節 //64位開啓指針壓縮下對象頭12字節,int佔4字節,引用佔4字節,對齊後佔24字節 class D{ int i; String str; } //32位下對象頭8字節,int4字節,byte佔1字節,引用佔4字節,對其後,共24字節 //64位開啓指針壓縮下對象頭12字節,int佔4字節,引用佔4字節,byte佔1字節,對齊後佔24字節 class E{ int i; byte b; String str; } /** * 對齊有兩種 * 一、整個對象8字節對齊 * 二、屬性4字節對齊 **** * * 對象集成屬性的排布 * markword 4 8 * class指針 4 4 * 父類的父類屬性 1 1 * 屬性對齊 3 3 * 父類的屬性 1 1 * 屬性對齊 3 3 * 當前類的屬性 1 1 * 屬性對齊填充 3 3 * 整個對象對齊 8+12 =》 24 12+12=》24 */ class O{ byte b; } class P extends O{ byte b; } class Q extends P{ byte b; }