Java对象内存布局和对象头
对象在堆内存的布局
- 对象内部结构分为:对象头、实例数据、对齐填充(保证8个字节的倍数)
- 对象头分为对象标记(markOop)和类元信息(klassOop),类元信息存储的是指向该对象类元数据(klass)的首地址
对象头
对象标记(mark word)
存储内容 | 标志位 | 状态 |
---|---|---|
对象哈希码,分代年龄 | 01 | 未锁定 |
指向锁记录的指针 | 00 | 轻量级锁定 |
指向重量级锁的指针 | 10 | 膨胀(重量级锁定) |
空,不需要记录信息 | 11 | GC标记 |
偏向线程ID,偏向时间戳,对象分代年龄 | 01 | 可偏向 |
- 默认存储对象的 HashCode、分代年龄和锁标志位等信息
- 这些信息都是与对象自身定义无关的数据,所以MarkWord被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据
- 它会根据对象的状态复用自己的存储空间,也就是说在运行期间MarkWord里存储的数据会随着锁标志位的变化而变
类元信息(又叫类型指针)
对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
对象头多大
在64位系统中,Mark Word占了8个字节,类型指针占了8个字节,一共是16个字节
压缩指针
实例数据
存放类的属性(Field)数据信息,包括父类的属性信息
如果是数组的实例部分还包括数组的长度,这部分内存按4字节对齐
对齐填充
虚拟机要求对象起始地址必须是8字节的整数倍
填充数据不是必须存在的,仅仅是为了字节对齐,这部分内存按8字节补充对齐