数组对象头包含Mark Word(8字节)、Class Pointer(压缩指针下4字节,否则8字节)和Array Length(固定4字节),三者共同构成对象头,其中Length是数组区别于普通对象的核心标志。

一维数组在 Java 中本质是对象,所以它的内存布局严格遵循 JVM 对象的三段式结构:对象头(Header)、数据体(data)、对齐填充(Padding)。其中对象头带来的固定开销,是理解数组内存占用的关键起点。
对象头包含哪些部分
对于数组对象,对象头一定包含三项内容:
-
Mark Word:存储锁状态、GC年龄、哈希码等运行时信息。64位 HotSpot JVM 默认占 8 字节(未开启压缩指针);开启
-XX:+UseCompressedOops后仍为 8 字节(Mark Word 大小与指针压缩无关) -
Class Pointer:指向
int[].class等数组类元数据的指针。开启压缩指针(默认开启)时占 4 字节;否则占 8 字节 - Array Length:数组长度字段,固定占 4 字节,且紧挨着 Class Pointer 存放
对象头总大小不是固定的
实际对象头字节数取决于 JVM 参数和平台:
- 64位 JVM + 压缩指针(最常见配置):8(Mark Word) + 4(Class Pointer) + 4(length) = 16 字节
- 64位 JVM + 关闭压缩指针:8 + 8 + 4 = 20 字节,但 JVM 会自动向上对齐到 8 的倍数 → 实际占 24 字节
- 32位 JVM:Mark Word 4 字节 + Class Pointer 4 字节 + length 4 字节 = 12 字节
注意:length 字段虽小,却是数组区别于普通对象的核心标志——没有它,JVM 就无法做边界检查或支持 arr.length。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
数据体前的隐式对齐要求
对象头之后不是直接接数据,而是可能插入填充字节(Padding),确保整个对象起始地址是 8 字节对齐的,且数据体(即第一个元素)也满足自然对齐(如 int 要求 4 字节对齐,long 要求 8 字节对齐)。
- 例如:16 字节对象头后,若下一个
int元素要从地址 0x1010 开始(4 字节对齐已满足),则无需额外 padding - 但若对象头为 24 字节,而元素类型是
long,JVM 可能再加 0–7 字节 padding,使数据体起始地址是 8 的倍数
这意味着即使一个 new int[0](空数组),也会占用至少 16 字节(压缩指针下)+ 可能的 padding,通常实测为 24 字节(含 8 字节填充)。
为什么不能忽略这十几字节
在高频创建小数组场景中,对象头开销会显著放大内存压力:
-
new int[1]:对象头 16B + 1×4B 数据 + padding → 实际约 24B -
new int[1]占用是纯数据(4B)的 6 倍 - 循环中每轮新建
new int[4],10 万次就多分配约 (24−16)×10⁵ = 0.8MB 冗余内存(仅头开销)
这不是理论损耗——它直接影响 GC 频率、缓存局部性,甚至在 Netty 或高性能序列化中被专门规避(如复用缓冲区、改用 ByteBuffer)。

















