写在前面
看了网上很多描述,其实已经写的很详细了,但是自己没有实践过总是觉得有点蒙蒙的
概念
Java对象的内存布局:对象头(Header),实例数据(Instance Data)和对齐填充(Padding)。
虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据,如hashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。这部分数据的长度在32位和64的虚拟机(未开启指针压缩)中分别为4B和8B,官方称之为”Mark Word”。
对象的另一部分是类型指针(kclass),即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例。另外如果对象是一个Java数组,那再对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中却无法确定数组的大小。
对象头在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。
个人测试:
Mark Word | kclass | 实例数据 | 引用 | Padding | |
32位 | 4Byte | 4Byte | 未测试过 | ||
64位未开启指针压缩 | 8Byte | 8Byte | 8Byte | ||
64位开启指针压缩 | 8Byte | 4Byte | 4Byte |
CASE
public class Peason {
private int age;
}
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
Peason a = new Peason();
System.out.println(ObjectSizeUtil.sizeOf(a));
Peason[] array = new Peason[1];
System.out.println(ObjectSizeUtil.sizeOf(array));
array = new Peason[2];
System.out.println(ObjectSizeUtil.sizeOf(array));
}
}
结果:
64位未开启指针压缩
24
32
40
原因:
24:Mark Word 8字节 + kclass 4字节 + 4字节的padding填充 + 4字节实例数据+4字节padding填充
32:Mark Word 8字节 + kclass4字节 + 4字节padding填充 + 4字节数组长度 + 4字节padding填充+8字节引用
40:Mark Word 8字节 + kclass4字节 + 4字节padding填充 + 4字节数组长度 + 4字节padding填充+8字节引用 + 8字节引用
64位开启指针压缩
16:Mark Word 8字节 + kclass 4字节 + 4字节实例数据
24:Mark Word 8字节 + kclass4字节 + 4字节数组长度 + 4字节引用 + 4字节padding填充
24:Mark Word 8字节 + kclass4字节 + 4字节数组长度 + 4字节引用 + 4字节引用