Java二维数组本身非缓存结构,但可通过列前缀和、滚动数组、ThreadLocal复用一维临时数组、一维连续布局及避免包装类等手段,提升局部性、降低GC开销并优化缓存行利用率。

Java 中二维数组本身不是缓存结构,但它能作为底层载体,支撑轻量、场景化、面向计算过程的缓存策略。关键不在于“把二维数组当缓存用”,而在于利用其内存布局与访问模式,减少重复计算、复用中间结果、降低 GC 开销——这才是实战中真正有效的“缓存思维”。
用列前缀和数组缓存列区间和
在二维最大子矩阵和等算法中,频繁计算某两行之间每列的和是性能瓶颈。直接嵌套循环累加效率低,而用列方向前缀和数组可将每次查询降为 O(1):
- 预建
colPrefix[i][j]:表示第 j 列前 i 行元素之和,初始化只需一次 O(rows×cols) 遍历 - 查询 [top, bottom] 区间第 j 列和:直接算
colPrefix[bottom + 1][j] - colPrefix[top][j] - 若内存敏感,改用滚动
tempColSum[j]数组:每次 top 固定时,bottom 递增过程中逐行累加,复用上一轮值,空间从 O(rows×cols) 降至 O(cols)
用一维临时数组缓存压缩行状态
二维问题常通过“枚举上下边界 → 压缩为一维 → 跑 Kadane”来降维。这个压缩过程产生的临时一维数组,就是天然的缓存单元:
- 避免每次重新 new int[cols],改用 ThreadLocal
池管理,如 ThreadLocal.withInitial(() -> new int[MAX_COLS]) - 每次获取后调用
Arrays.fill(buf, 0)复位,跳过对象分配与 GC 扫描 - 若需多次回溯(如调试时查起始列),可额外缓存
dp[j](以 j 结尾的最大子段和)和start[j](对应起始位置),空间换时间
用一维数组模拟替代提升缓存行利用率
当二维数组用于密集数值计算(如图像卷积、矩阵乘),int[][] 的“数组的数组”结构会破坏跨行局部性。此时应主动放弃语法便利,改用一维连续布局:
立即学习“Java免费学习笔记(深入)”;
- 声明
int[] data = new int[rows * cols],保证所有元素物理连续 - 按行主序映射:访问
[i][j]→data[i * cols + j];写入同理 - 封装成
Matrix类,对外保留get(i,j)/set(i,j,v)接口,内部隐藏索引逻辑 - 优势明显:L1/L2 缓存命中率提升,JIT 更易向量化,GC 压力下降
避开包装类与临时对象干扰缓存
缓存效果容易被隐式对象创建破坏。即使数组本身连续,遍历中混入对象也会打断 CPU 预取节奏:
- 禁用
Integer[][]替代int[][]:每个Integer是堆上独立对象,间接寻址彻底瓦解局部性 - 不在内层循环创建短命对象,如
new Point(i, j)或字符串拼接,TLAB 频繁分配会拖慢吞吐 - 若需结构化访问,定义紧凑的 flat class(字段对齐、无冗余 padding),或用 VarHandle 控制内存布局,防伪共享



















