java基本类型数组是堆上对象,内存布局为16字节对齐的对象头(含mark word和压缩类指针)+4字节length字段+元素数据区,总大小按8字节对齐。

Java中基本类型数组(如 int[]、byte[] 等)是对象,分配在堆上,其内存布局包含对象头 + 数组长度字段 + 实际元素数据。要精确量化开销,需区分 JVM 实现(主流为 HotSpot)、平台架构(32/64 位)、是否开启指针压缩(UseCompressedOops),以及数组长度对对齐的影响。
对象头大小:取决于 JVM 配置与平台
HotSpot 中,数组对象头由两部分组成:
- Mark Word(标记字段):8 字节(64 位 JVM 默认),存储哈希码、锁状态、GC 分代年龄等;若开启指针压缩(默认开启),仍为 8 字节(未压缩时也是 8 字节,32 位 JVM 则为 4 字节)。
-
Klass Pointer(类元数据指针):在开启指针压缩(
-XX:+UseCompressedOops)时占 4 字节;关闭时占 8 字节(64 位 JVM)。JDK 8+ 默认开启压缩,且从 JDK 15 起不可关闭(仅限某些特殊构建)。
因此,典型 64 位 HotSpot JVM(默认配置)下,对象头为 12 字节(8 + 4),但因 JVM 要求对象起始地址按 8 字节对齐,实际会**补齐到 16 字节**(即对象头区域占用 16 字节,其中最后 4 字节为填充)。
数组长度字段:固定 4 字节,不随类型变化
所有 Java 数组对象(包括基本类型和引用类型数组)都继承自 Object,但额外携带一个隐式 length 字段,用于支持 array.length 访问。该字段始终是 int 类型(4 字节),位于对象头之后、元素数据之前。
注意:它不单独占用新“字段槽”,而是作为数组对象的固有结构的一部分,紧邻对象头存放。因此,在 16 字节对象头对齐后,length 字段从偏移量 16 开始,占 4 字节(偏移 16–19)。
元素数据区:类型决定单元素字节数,总大小需对齐
基本类型数组的数据区连续存储原始值,无封装开销。各类型单元素大小如下:
-
boolean[]、byte[]:1 字节/元素 -
char[]、short[]:2 字节/元素 -
int[]、float[]:4 字节/元素 -
long[]、double[]:8 字节/元素
数据区总字节数 = length × elementSize。但整个数组对象(对象头 + length + 数据)的**总大小必须是 8 字节的整数倍**(HotSpot 的对象对齐粒度)。因此,若前两部分(16 + 4 = 20 字节)加数据长度不是 8 的倍数,会在数据末尾自动填充(padding)至对齐边界。
例如:new int[3] → 数据区 = 3 × 4 = 12 字节;前导 20 字节 + 12 = 32 字节,已是 8 的倍数,无需填充;new byte[1] → 20 + 1 = 21 → 向上对齐到 24,填充 3 字节。
实测验证方法:用 JOL(Java Object Layout)工具
最可靠的方式是使用 OpenJDK 官方推荐的 JOL 工具,避免手动推算误差:
mvn dependency:copy-dependencies -DoutputDirectory=lib java -cp "lib/jol-cli.jar:." org.openjdk.jol.vm.VM java -cp "lib/jol-cli.jar:." org.openjdk.jol.info.GraphLayout.parseInstance(new int[0]).toPrintable()
输出中关注 SIZE(总字节数)和 OFFSET 列,可清晰看到对象头、length 字段、数据起始位置及填充分布。
典型结果(JDK 17 / 64 位 / CompressedOops 开启):
-
new int[0]:SIZE = 16(仅对象头对齐,无数据,无 length 填充?注意:实际含 length 字段,但 0 元素时 total = 16 是错的 —— 正确应为 24:16(头)+4(length)+4(padding)→ JOL 显示为 24) -
new long[1]:16(头) + 4(length) + 8(data) = 28 → 对齐到 32,SIZE = 32
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











