Java对象内存布局和对象头
Java 对象内存布局和对象头
对象在堆内存中的布局
对象内部结构分为:对象头、实例数据、对齐填充(保证 8 个字节的倍数)
对象头分为对象标记(markOop)和类元信息(klassOop),类元信息存储的是指向该对象类元数据(klass)的首地址
- 对象头
- 对象标记
- 默认存储对象的 HashCode、分代年龄和锁标志位等信息,这些信息都是与对象自身定义无关的数据,所以 MarkWord 被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据,它会根据对象的状态复用自己的存储空间,也就是说在运行期间 MarkWord 里存储的数据会随着锁标志位的变化而变化
- 类元信息
- 对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
- 对象标记
- 实例数据
- 存放类的属性数据信息,包括父类的属性信息,如果是数组的实例部分还包括数组的长度,这部分内存按 4 字节对齐
- 对齐填充
- 虚拟机要求对象起始地址必须是 8 字节的整数倍,填充数据不是必须存在的,仅仅是为了字节对齐,这部分内存按 8 字节补充对齐
对象头有多大:在 64 位系统中,Mark Word 占了 8 个字节,类型指针占了 8 个字节,一共是 16 个字节
对象头的 MarkWord
使用 JOL 分析对象在 JVM 的大小和分布
1 | <dependency> |
参数 | 说明 |
---|---|
OFFSET | 偏移量,也就是到这个字段位置所占用的字节数 |
SIZE | 后面类型的字节大小 |
TYPE | 是 Class 中定义的类型 |
DESCRIPTION | DESCRIPTION 是类型的描述 |
VALUE | VALUE 是 TYPE 在内存中的值 |
可以看到,一个对象在内存中占用了 12 个字节和 4 个字节的填充(开启压缩的情况下,默认开启,关闭压缩使用 -XX:-UseCompressedClassPointers,关闭后占用 16 个字节,因为是 8 的整数倍,所以不需要填充)
添加变量 int(4byte) + double(8byte) + boolean(1byte) 后为 25 字节,填充 7 个字节,所以总共 32 个字节