java数组在jvm中本质是对象,其对象头比普通对象多出4字节array length字段,用于存储不可变长度并支持越界检查;对象头含mark word、klass pointer和array length三部分,堆中内存布局为对象头+元素数据区+对齐填充,栈中仅存引用地址。

Java 数组在 JVM 中本质是对象,它的内存布局严格遵循对象规范,但有专属结构——对象头里多出一个固定字段:数组长度。这个细节决定了数组不可变长、支持 length 属性访问,也影响内存对齐和 GC 行为。
数组对象头的三要素:Mark Word、Klass Pointer、Array Length
数组对象头比普通 Java 对象多一个 4 字节的 Array Length 字段,其余两部分与普通对象一致:
- Mark Word(通常 8 字节):存储哈希码、GC 分代年龄、锁状态等运行时信息;内容动态复用,随对象状态变化而切换语义
-
Klass Pointer(开启压缩指针为 4 字节,否则 8 字节):指向元空间中对应的 Class 对象,如
[I表示 int[],[Ljava.lang.String;表示 String[] -
Array Length(固定 4 字节 int):记录创建时指定的长度,写入后不可修改,JVM 通过它做越界检查(
ArrayIndexOutOfBoundsException)
堆中数组对象的完整内存结构
整个数组对象在堆中连续分布,按顺序排列为:
- 对象头(12 或 16 字节,取决于是否开启压缩指针 + 是否对齐填充)
- 元素数据区(紧接对象头之后):基本类型数组直接存值(如
int[5]存 5 个 4 字节整数),引用类型数组存对象引用地址(每个引用占 4 或 8 字节) - 对齐填充(如有):确保整个对象大小是 8 字节的整数倍;例如
byte[1]对象头 12 字节 + 数据 1 字节 = 13 字节,需补 3 字节凑成 16 字节
栈中引用与堆中数组的分离关系
声明如 int[] arr = new int[10]; 时:
- 变量
arr是局部变量,存于当前方法栈帧中,内容仅为一个 4/8 字节的内存地址 -
new int[10]整体分配在堆上,生命周期由 GC 管理,不依赖栈帧是否弹出 - 多个引用可指向同一数组(如
int[] b = arr;),它们共享同一块元素数据区,任一修改都会被对方看到
基本类型 vs 引用类型数组的关键差异
二者对象头结构完全相同,区别只在元素数据区的语义和占用方式:
-
基本类型数组(如
long[3]):数据区直接存放原始值,共 3 × 8 = 24 字节,无额外对象开销 -
引用类型数组(如
String[3]):数据区存放 3 个引用(各 4 或 8 字节),String 实例本身仍独立存在于堆中,数组不持有其内容 - 注意:
String[] a = new String[3];创建的是含 3 个 null 引用的数组,不创建任何 String 实例
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











