Java的int[][]是“数组的数组”,非真正多维数组:先分配1000个引用的外层数组,再为每个引用单独分配500元素的内层数组,内存不连续,访问需两次解引用且缓存命中率低。
![多维数组的内存结构:分析 int[][] 为什么在内存中表现为“数组的数组”,其空间连续性如何](https://img.php.cn/upload/article/001/242/473/177865142155456.jpeg)
Java 中的 int[][] 不是真正意义上的多维数组,而是“数组的数组”——外层是一个一维引用数组,每个元素指向一个独立的 int[] 对象。这种结构直接决定了它在内存中不连续。
为什么叫“数组的数组”?
声明 int[][] matrix = new int[1000][500]; 时,JVM 实际执行两步:
- 先分配一个长度为 1000 的
int[]引用数组(外层数组),存放在堆中; - 再为该数组的每个位置(共 1000 个)分别
new int[500],生成 1000 个彼此独立的int[]对象。
这些内层数组对象没有位置约束,可能分散在堆内存的不同区域,甚至跨内存页。它们之间没有物理关联,仅靠外层数组中的引用维系逻辑关系。
空间连续性:完全不连续
与 C 语言中 int a[1000][500] 分配一块连续的 2MB 内存不同,Java 的 int[][]:
- 外层数组本身是连续的(1000 个引用,每个 4 或 8 字节);
- 但每个引用所指向的内层数组,各自占据一段独立、不相连的内存块;
- 整体布局像“一串指针 + 散落的盒子”,而非“一块大平板”。
这意味着按行遍历(i 变化慢、j 变化快)时,缓存还能局部受益;但一旦按列遍历(j 变化快),每次都要跳转到不同内存页,缓存命中率急剧下降。
访问开销:两次解引用 + 缓存失效
执行 matrix[i][j] 需要:
- 从外层数组读出第
i个引用(一次内存加载); - 根据该引用定位到对应内层数组对象头(可能触发 TLB 查找或 GC 页表检查);
- 再在该数组中计算偏移
j * 4并读取值(第二次内存加载)。
这比 C 中单次地址计算 base + i*500*4 + j*4 多出至少一次随机访存,且无法被 CPU 预取器有效识别。
对比 C 的连续二维布局
C 的二维数组本质就是一维展开:a[i][j] 等价于 *(base + i * cols + j)。所有元素严格按行优先顺序紧挨着存放,64 字节缓存行能一次性载入多个相邻元素,大幅提升吞吐效率。Java 的 int[][] 没有这种保障,连续性只存在于每行内部,行与行之间断裂。

















