对于Java虚拟机,我们都知道它的内存区域分为:堆、方法区、虚拟机栈等区域。但是一个对象在Java虚拟机中是如何存储的,相信很少有人会比较清楚。JVM中Java对象的内存布局是我们理解并发编程的同步机制的基础。在HotSpot虚拟机中,对象在内存中的布局可以分为三个区域:对象头(Header)、实例数据(InstanceData)和对齐填充(Padding)。对象头HotSpot虚拟机的对象头包括两部分信息,第一部分用于存放运行时的数据,第二部分用于存放类型指针。运行时数据对象头第一部分用于存放对象本身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳、etc.这部分数据的长度在32位和64位虚拟机中分别是32bit和64bit,官方称之为“MarkWord”。为了提高虚拟机的空间效率,MarkWord被设计成一个非固定的数据结构,让不同的数据以不同的状态存储,从而节省数据空间。MarkWord在不同状态下存储的内容如下表所示。Java对象的内存布局如上表所示。在32位的HotSpot虚拟机中,如果对象没有被锁定(标志位为01),那么MarkWord中存储的是“对象哈希码,对象世代年龄”。32位空间中的25位用于存储对象的哈希码,4位用于存储对象的世代年龄,2位用于存储锁定标志,1位固定为0。类型指针对象头的第二部分是类型指针,即对象指向其类元数据的指针,虚拟机通过这个指针来判断该对象是哪个类的实例。另外,如果对象是Java数组,那么对象头中必须有一段数据记录数组的长度,因为虚拟机可以通过普通Java对象的元数据信息来确定Java对象的大小,但是从数组的元数据信息来看,数组的大小是无法确定的。实例数据实例数据部分是对象实际存储的有效信息,包括程序中各个类型的字段类型,无论是从父类继承还是在子类中定义。一般来说,父类定义的变量总是出现在子类之前。alignmentpadding对象的padding部分不一定存在也没有特殊意义,只是起到占位符的作用。因为HotSpotVM的自动内存管理系统要求对象的起始地址必须是8字节的整数倍,换句话说,对象的大小必须是8字节的整数倍。对象头部分恰好是8字节的倍数(1倍或2倍),因此,当对象实例数据部分不对齐时,需要通过对齐填充来完成。小结在本文中,我们介绍了Java对象在JVM中的内存布局,可以分为三个部分:对象头、实例数据和对齐填充。对象头的第一部分包括对象运行时数据和类型指针。对象运行时数据包括:hashcode、GCgenerationalage、lockstatusflag等,类型指针指向对象类型元数据,判断对象是哪个类的实例。第二部分是实例数据,是实际存储的有效信息,包括各种类型的字段。第三部分是alignmentpadding,因为JVM要求对象的起始地址必须是8字节的整数倍,所以必须有alignmentpadding来占用空间。深入理解Java对象的内存布局
