JVM 对象大小
对象头在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