Java基本类型数组内存布局:为何存在额外填充字节?
嘿,这个问题的核心其实是你对HotSpot虚拟机的对象对齐粒度有个小误解——咱们先把这个点厘清,再一步步拆解内存布局:
首先纠正关键认知:HotSpot默认对象对齐粒度是16字节,而非8字节
你提到“已知对象遵循8字节对齐规则”,这是个很常见的混淆点。HotSpot虚拟机的默认对象内存对齐粒度是16字节,也就是说,所有对象的总大小必须是16字节的整数倍。如果需要调整这个规则,可以通过JVM参数-XX:ObjectAlignmentInBytes修改(取值必须是2的幂,范围8-256)。
拆解两种数据模型下的数组内存布局
结合你给出的JOL输出,我们逐个计算:
1. X86_32_DataModel(32位无压缩指针)
数组对象的内存结构分为三部分:对象头 + 数组元素 + 对齐填充
- 对象头:32位环境下,对象头包含3个部分:mark word(4字节)、klass指针(4字节)、数组长度(4字节),加起来总共12字节
- 数组元素:int[10]有10个int类型元素,每个int占4字节,总大小是
10×4=40字节 - 当前总大小:
12+40=52字节 - 对齐填充计算:因为要对齐到16字节的整数倍,52之后的下一个16的倍数是64(
16×4),所以需要填充64-52=12字节——这就是你看到的外部填充12字节,最终实例大小为64字节。
2. X86_64_COOPS_DataModel(64位压缩指针)
同样按结构拆解:
- 对象头:64位压缩指针模式下,对象头包含mark word(8字节)、压缩后的klass指针(4字节)、数组长度(4字节),加起来总共16字节(对应你输出里的4个4字节头字段)
- 数组元素:同样是40字节
- 当前总大小:
16+40=56字节 - 对齐填充计算:56之后的下一个16的倍数是64,所以需要填充
64-56=8字节——这就是你看到的外部填充8字节,最终实例大小为64字节。
额外验证:修改对齐粒度为8字节的情况
如果通过-XX:ObjectAlignmentInBytes=8把对齐粒度改成8字节:
- 32位环境下,52之后的下一个8的倍数是56,只需要填充4字节,实例大小会变成56字节
- 64位压缩指针环境下,56已经是8的倍数,无需填充,实例大小就是56字节
这样就能完美解释你看到的填充差异啦!
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

