1. 概述

本文将深入探讨 HotSpot JVM 是如何存储数组长度的,以及它在内存中的具体位置。

需要明确的是,JVM 运行时数据区的内存布局 并不在 JVM 规范中强制定义,而是由具体实现者自行决定(参考 JVM 规范)。这意味着不同的 JVM 实现可能采用完全不同的对象和数组内存布局策略。

本文聚焦于一个特定实现:HotSpot JVM。后续内容中,“JVM”一词如无特别说明,均指 HotSpot JVM。

2. 依赖准备

要查看 JVM 中数组的实际内存布局,我们将使用 Java Object Layout(简称 JOL)工具。它是 OpenJDK 提供的轻量级分析工具,能精准展示对象在堆中的分布。

需要引入以下 Maven 依赖:

<dependency> 
    <groupId>org.openjdk.jol</groupId> 
    <artifactId>jol-core</artifactId>    
    <version>0.10</version> 
</dependency>

3. 数组长度的存储位置

核心结论:HotSpot JVM 将数组长度直接存储在对象头(Object Header)中。

HotSpot 使用一种叫 OOP(Ordinary Object Pointer) 的数据结构来表示对象指针。对于数组,它使用一种特殊的 OOP 类型 —— arrayOop。每个 arrayOop 的对象头包含以下三部分:

  • Mark Word:用于存储哈希码、GC 分代信息、锁状态等
  • Klass Word:指向类元数据(Klass)的指针
  • Array Length4 字节的数组长度字段

⚠️ 注意:长度字段固定为 4 字节,这意味着数组最大长度受限于 Integer.MAX_VALUE(2^31 - 1),这也是为什么 Java 数组长度不能超过 int 范围的根本原因。

验证实例

我们通过 JOL 工具打印一个 int[42] 的内存布局:

int[] ints = new int[42];
System.out.println(ClassLayout.parseInstance(ints).toPrintable());

输出结果如下:

[I object internals:
 OFFSET  SIZE   TYPE DESCRIPTION               VALUE
      0     4        (object header)           01 00 00 00 (00000001 00000000 00000000 00000000) (1) # mark
      4     4        (object header)           00 00 00 00 (00000000 00000000 00000000 00000000) (0) # mark
      8     4        (object header)           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363) #klass
     12     4        (object header)           2a 00 00 00 (00101010 00000000 00000000 00000000) (42) # array length
     16   168    int [I.<elements>             N/A
Instance size: 184 bytes

🔍 关键点解析:

  • OFFSET 0-7:Mark Word(8 字节,64位 JVM 下通常拆成两个 4 字节)
  • OFFSET 8-11:Klass Word(4 字节)
  • OFFSET 12-15:✅ Array Length(4 字节),值为 42
  • OFFSET 16 起:数组元素区,每个 int 占 4 字节,42 个共 168 字节
  • 总大小 184 字节 = 16(对象头)+ 168(元素)

这个布局清晰地证明了:数组长度是对象头的一部分,紧跟在 klass word 之后

小结:内存布局结构

+---------------------+
| Mark Word     (8B)  |
+---------------------+
| Klass Word    (4B)  |
+---------------------+
| Array Length  (4B)  |  ← 长度就在这!
+---------------------+
| Element[0]    (4B)  |
| Element[1]    (4B)  |
|     ...             |
| Element[41]   (4B)  |
+---------------------+

这种设计简单粗暴但高效 —— 获取数组长度只需一次内存偏移访问,无需遍历或额外计算。

4. 总结

  • ✅ HotSpot JVM 将数组长度作为对象头的一部分,存储在 arrayOop 结构中
  • ✅ 长度字段占 4 字节,类型为 int,因此最大长度为 Integer.MAX_VALUE
  • ✅ 使用 JOL 工具可直观验证内存布局,是分析 JVM 底层机制的利器
  • ❌ 不要误以为长度是通过方法计算或存在单独字段中 —— 它是 JVM 层面的元数据

所有示例代码均可在 GitHub 获取:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-jvm-2


原始标题:Where Is the Array Length Stored in JVM?