为什么Java8环境下char[1024]数组的浅大小为2072字节?

内存大小偏差原因
8字节的偏差来自两点:一是你对HotSpot数组对象的内存布局认知有误,错误计入了不存在的引用字段,也没考虑压缩指针开关对对象头大小的影响;二是没有结合当前JVM的实际运行参数计算内存占用。
HotSpot数组对象的内存布局规则
Oracle JDK/OpenJDK默认使用的HotSpot虚拟机,堆中对象的内存分配遵循两个核心规则:
- 所有对象的内存起始地址必须是8字节的整数倍,对象总大小不足8字节整数倍的部分,会用填充位补齐
- 数组类型的对象头固定由三部分组成,不存在你提到的单独“引用字段”:
- Mark Word:固定占8字节,存储对象哈希码、GC分代年龄、锁标记等运行时元数据
- Klass Pointer:指向对象所属类元数据的指针,开启
-XX:+UseCompressedOops(压缩普通对象指针)时占4字节,关闭时占8字节 - 数组长度字段:int类型,固定占4字节,为数组对象独有
- 数组的实例数据段就是连续存储的数组元素,char类型每个元素固定占2字节
对应2072字节的实际计算
你当前的JDK 1.8.0_333环境处于关闭压缩对象指针的状态,char[1024]的内存计算过程为:
- 对象头大小:8字节Mark Word + 8字节未压缩Klass Pointer + 4字节长度字段 = 20字节
- 元素存储大小:
1024 * 2 = 2048字节 - 对齐填充:20 + 2048 = 2068字节,不是8的整数倍,需要填充4字节到最近的8的倍数,即2072字节,和你在hprof中观测到的结果完全一致。
压缩指针关闭的常见原因
JDK 8默认开启压缩指针,但两种场景下会关闭:
- 启动JVM时手动指定了
-XX:-UseCompressedOops参数 - 配置的最大堆内存(-Xmx)超过32GB,此时32位偏移量无法覆盖全堆地址空间,HotSpot会自动关闭压缩指针。
你之前算出的2064字节,是开启压缩指针时的char[1024]大小:此时对象头为8+4+4=16字节,加2048字节元素总大小为2064,本身就是8的倍数不需要填充,这也是大多数默认小堆配置下JDK8的常规表现。
内容的提问来源于stack exchange,提问作者CoXier
相关产品推荐
相关产品推荐

