Java数组内存占用由对象头(16字节)、元素数据区(长度×单元素大小)和末尾对齐填充三部分组成,需在64位JVM指针压缩启用前提下计算,总大小必须为8字节倍数。
Java 数组内存占用不是简单用“元素个数 × 单个元素大小”就能算准的。它由三块组成:数组对象头、元素数据区、以及为对齐补的填充字节。64 位 JVM 默认开启指针压缩(-XX:+UseCompressedOops),这是计算前提;若堆超过 32GB 或显式关闭压缩,引用和类指针会翻倍,结果完全不同。
数组是对象,但它比 new Object() 多一个字段——长度(length)。所以它的对象头固定包含三部分:
length 值合计 16 字节。这是所有数组的起点,与元素类型无关。
这一部分是真正存数据的地方,大小 = 数组长度 × 单元素字节数。注意区分基本类型和引用类型:
立即学习“Java免费学习笔记(深入)”;
int[5] → 5 × 4 = 20 字节;long[3] → 3 × 8 = 24 字节String[10] 的元素区是 10 × 4 = 40 字节;每个 String 对象另算(通常 24–40+ 字节)字段排列遵循自然对齐(如 long 对齐到 8 字节边界),但数组元素是连续同构的,不涉及内部字段重排,因此无需考虑字段间填充。
JVM 要求每个对象总大小必须是 8 的倍数,以提升 CPU 缓存访问效率。填充只发生在最后,补足即可:
padding = (8 - (header + data) % 8) % 8
int[2] → 头 16B + 数据 8B = 24B → 24 % 8 == 0 → 填充 0Bbyte[1] → 头 16B + 数据 1B = 17B → 补 7B → 总 24B常见误区:误把填充当成“每字段后都补”,其实只在对象末尾一次性补齐。
以 new int[3] 为例(64 位 + 指针压缩):
再看 new Integer[1](注意是包装类数组):
Integer 引用)Integer 对象本身(它另占约 16 字节)不复杂但容易忽略。