CPU cache 是什么?
Source: Dev.to
CPU 缓存概述
Cache 用中文可以说成“临时存储区”。CPU 中有 L1、L2、L3 缓存,分别是
- L1 – 每个核心自动拥有(容量 ≈ 32 KB)
- L2 – 每个核心拥有(容量 ≈ 256 KB)
- L3 – 所有核心共享的缓存(容量很大)
CPU 在读取一条指令时会先在 L1 缓存中查找。如果在 L1 中找到了数据,可以在 3‑5 个周期内取出,速度非常快。若 L1 未命中,则继续在 L2(10‑15 周期)查找;若仍未命中,则去 L3(50‑100 周期)继续查找。
缓存友好代码
在 C++ 中,缓存友好的基本做法是 row‑major 访问。
不友好(cache‑unfriendly)代码
for (int col = 0; col < N; ++col) {
for (int row = 0; row < N; ++row) {
sum += matrix[row][col];
}
}
缓存高效(row‑major)代码
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
sum += matrix[row][col];
}
}
为什么 row‑major 访问是缓存友好的?
二维数组示例
int matrix[4][4] = {
{ 1, 2, 3, 4}, // row 0
{ 5, 6, 7, 8}, // row 1
{ 9, 10, 11, 12}, // row 2
{13, 14, 15, 16} // row 3
};
内存布局(地址)
| 元素 | 值 | 地址 |
|---|---|---|
| matrix[0][0] | 1 | 0x1000 |
| matrix[0][1] | 2 | 0x1004 |
| matrix[0][2] | 3 | 0x1008 |
| matrix[0][3] | 4 | 0x100C |
| matrix[1][0] | 5 | 0x1010 |
| matrix[1][1] | 6 | 0x1014 |
| matrix[1][2] | 7 | 0x1018 |
| matrix[1][3] | 8 | 0x101C |
| matrix[2][0] | 9 | 0x1020 |
| matrix[2][1] | 10 | 0x1024 |
| matrix[2][2] | 11 | 0x1028 |
| matrix[2][3] | 12 | 0x102C |
| matrix[3][0] | 13 | 0x1030 |
| matrix[3][1] | 14 | 0x1034 |
| matrix[3][2] | 15 | 0x1038 |
| matrix[3][3] | 16 | 0x103C |
在 C++ 中采用 row‑major 排列时,同一行内的元素在内存中相邻,间隔为 4 bytes(int)。
CPU 在首次访问 matrix[0][0] 时,如果未命中,会一次性把 64 byte 大小的 cache line 从内存加载进来。这个 cache line 包含 matrix[0][0]、matrix[0][1]、matrix[0][2]…,即整行的数据。因此在循环中访问 matrix[0][1]、matrix[0][2] 等时,CPU 能直接从缓存中以 4 bytes 的步长快速读取,显著提升执行速度。