對象頭在32位系統上占用8B,64位系統上占16B。 無論是32位系統還是64位系統,對象都采用8字節對齊。Java在64位模式下開啟指針壓縮,比32位模式下,頭部會大4B(mark區域變位8B,kclass區域被壓縮),如果沒有開啟
指針壓縮,頭部會大8B(mark和kclass都是8B),換句話說, HotSpot的對齊方式為8字節對齊:
(對象頭+實例數據+padding)%8 等於0 且 0<=padding<8。以下說明都是以HotSpot為基准。
- 在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字節。
- 靜態屬性不算在對象大小內。
下面來通過示例來驗證一下
pom.xml添加依賴
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.9</version> </dependency>
(1)示例
public class ObjLockTest { public static void main(String[] args) { Object o = new Object(); System.out.println("new Object:" + ClassLayout.parseInstance(o).toPrintable()); } }
控制台輸出:
new Object:java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
分析:
首先對象頭是包含
MarkWord和
類型指針這兩部分信息的;
根據64位開啟指針壓縮的情況下,存放Class指針的空間大小是4字節,MarkWord是8字節,對象頭為12字節;
根據公式:對象實例的大小 = 對象頭 + 實例數據 + 對齊填充。即 12b對象頭 + 0b實例數據 + 4b對齊填充
結論:新建Object對象,會在內存占用16個字節,其中Header占12個(markword占8個+classpointer占4個),沒有實例數據,補充對齊4個。
(2)示例:
public class ObjLockTest { public static void main(String[] args) { A a = new A(); System.out.println("new A:" + ClassLayout.parseInstance(a).toPrintable()); a.setFlag(true); a.setI(1); a.setStr("ABC"); System.out.println("賦值 A:" + ClassLayout.parseInstance(a).toPrintable()); } static class A { private boolean flag; private int i; private String str; public void setFlag(boolean flag) { this.flag = flag; } public void setStr(String str) { this.str = str; } public void setI(int i) { this.i = i; } } }
控制台輸出:
new A:com.lock.ObjLockTest$A object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 73 c9 00 f8 (01110011 11001001 00000000 11111000) (-134166157) 12 4 int A.i 0 16 1 boolean A.flag false 17 3 (alignment/padding gap) 20 4 java.lang.String A.str null Instance size: 24 bytes Space losses: 3 bytes internal + 0 bytes external = 3 bytes total 賦值 A:com.lock.ObjLockTest$A object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 73 c9 00 f8 (01110011 11001001 00000000 11111000) (-134166157) 12 4 int A.i 1 16 1 boolean A.flag true 17 3 (alignment/padding gap) 20 4 java.lang.String A.str (object) Instance size: 24 bytes Space losses: 3 bytes internal + 0 bytes external = 3 bytes total
新建對象A時,中Header占12個(markword占8個+classpointer占4個),實例數據中 boolean占一個字節,會補齊三個,int占4個,String占8個,無需補充對齊。
例如:
class C{ A a; B b; }
對象的大小 = 12B對象頭 + 4B*2的實例數據 + 4B的填充 = 24B
class C{ A a; B b; D d; }
對象的大小 = 12B對象頭 + 4B*3的實例數據 + 0B的填充 = 24B