行遍历快的根本原因是缓存命中率高:CPU按64字节缓存行加载数据,行优先存储使同行元素地址连续,行遍历时能高效复用缓存行;列遍历则导致频繁缓存未命中和额外指针跳转,实测慢10倍以上。

行遍历快的根本原因是缓存命中率高
CPU访问内存时,不会只读一个int,而是把连续64字节(典型缓存行大小)一起加载进L1 cache。C++中二维数组(包括int arr[1000][1000]或std::vector<:vector>></:vector>的每行)按行优先布局:同一行元素地址连续,同一列元素地址相隔整行长度(如1000×sizeof(int) = 4000字节)。行遍历时,arr[i][j]和arr[i][j+1]大概率落在同一缓存行;列遍历时,arr[i][j]和arr[i+1][j]地址跳变大,几乎每次都要触发新缓存行加载,甚至跨页。
vector>按列遍历会额外放大性能损失
动态二维vector不是一块连续内存,而是“指针数组 + 每行独立堆块”。列遍历不仅破坏空间局部性,还导致:
- 每次
matrix[i][j]都要先解引用外层vector拿到行首指针,再加偏移——多一次指针跳转 - 不同行可能分布在不同内存页,列遍历引发频繁缺页中断(page fault)
- 编译器很难对这种双重间接访问做优化(如循环展开、向量化)
std::vector<int></int>一维模拟二维(data[i * cols + j])能完全避免指针跳转,行遍历优势更明显。实测差异远不止“一点点”
在1000×1000的int数组上做简单求和,典型表现:
- 行遍历(
for i; for j):约3–5ms - 列遍历(
for j; for i):常达40–80ms,慢10倍以上 - 若数组更大(如4000×4000)或运行在低缓存机器上,差距可扩大到20倍
什么时候可以忽略这个差异?
只有当以下条件同时满足时,列优先才不至于严重拖慢:
- 数组极小(如
int arr[4][4]),整个数组能塞进一级缓存 - 访问频率极低(比如初始化后只读一次)
- 逻辑强依赖列语义(如转置、列归一化),且已用分块(tiling)等技术缓解


















