在HotSpot虚拟机中,对象在堆内存的存储布局可以分为:对象头(Header) 实例数据(Instance Data),对齐填充(Padding)
对象头(Header)
对象头部分包括两类信息
第一类:存储对象自身运行时的数据,如HashCode,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等,这些数据在JVM中被称为“Mark Word”
Mark Word被设计为一种有着动态定义的数据结构,根据对象的状态复用自己的存储空间。如在32位HotSpot,若对象未被同步锁锁定的状态下,MarkWord的32位比特存储空间的25个比特位用于存储对象HashCode,4比特位用于存储对象分代年龄,2比特位用于存储锁对标志位,一个比特位固定为0
HotSpot虚拟机对象头MarkWord
存储内容 | 标志位 | 状态 |
HashCode,GC分代年龄 | 01 | 未锁定 |
指向锁记录的指针 | 00 | 轻量级锁定 |
指向重量级锁的指针 | 10 | 膨(重量级锁定) |
空,不需要记录信息 | 11 | GC标记 |
偏向线程ID,偏向时间戳,对象分代年龄 | 01 | 可偏向 |
第二类:是类型指针,即对象指向它的类型元数据的指针,java虚拟机通过指针来确定该对象是那个类的实例,但并不是所有的虚拟机实现都必须在你对象数据上保留类型指针。
此外,如果对象是数组,则对象头中还必须记录数组长度
实例数据(Instance Data)
是对象真正存储的有效信息,即程序中定义的各种类型的字段内容(包括父类继承的,子类定义的)。在HotSpot虚拟机的默认分配顺序是:longs/doubles,ints,shorts/chars,tytes/booleans,oops(Ordina Object Pointers),相同宽度的字段总是被分配到一起,在满足这个前提下,父类的变量出现在子类前。当然也可以通过设置CompactFields参数,来使子类的短类型数据插入父类的变量空隙中,来节约内存
对齐填充
HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的倍数,因此当对象结束地址不能整除8使,需要在对象尾通过对齐填充来补全