首页/计算机组成原理/存储器/局部性原理 🔗 在 Obsidian 中打开
计算机组成原理 · 存储器

局部性原理

重要度 ⭐⭐⭐⭐⭐存储器层次结构Cache存储层次存储器
速查
时间局部性:刚访问的数据很可能再次被访问(循环);空间局部性:访问某地址后附近地址也很可能访问(数组顺序遍历)。两者共同支撑 Cache 高效工作。

速查

项目
时间局部性最近访问的数据可能再次被访问
空间局部性访问某地址后,附近地址也可能被访问

1. 基本概念

局部性原理是存储器层次结构的理论基础。程序对存储器的访问不是随机的,而是呈现聚集性。

时间局部性(Temporal Locality)

  • 刚被访问的数据很可能在近期再次被访问
  • 原因:循环、重复调用的函数 / 变量

空间局部性(Spatial Locality)

  • 刚被访问的数据附近的数据很可能在近期被访问
  • 原因:顺序执行的指令、数组遍历

2. 典型场景中的局部性

数组求和(空间局部性强)

for (i = 0; i < N; i++) sum += A[i];  // 顺序访问,空间局部性好
+ sum 体现时间局部性(每轮都访问)

矩阵乘法(两种局部性)

C[i][j] += A[i][k] * B[k][j];
A 按行访问 → 空间局部性好
B 按列访问 → 空间局部性差(跳跃)

链表遍历(局部性差)

while (p) { process(p->data); p = p->next; }
// 节点在内存中不连续 → 空间局部性差

3. 局部性与存储层次

层次结构:寄存器 → L1 → L2 → L3 → 主存 → 磁盘。局部性如何支撑它:

  • 时间局部性 → Cache 保留最近使用的数据
  • 空间局部性 → Cache 按块(Cache Line)加载数据
关键Cache 的工作原理正是利用了程序的局部性。

4. Cache 命中率与局部性

$$T_{avg} = h \times T_{hit} + (1-h) \times T_{miss}$$
程序特征局部性Cache 命中率
顺序遍历数组空间局部性极好> 99%
循环执行代码时间局部性极好> 99%
随机访问局部性差< 50%
链表遍历空间局部性差较低

5. 手算示例

例 1:命中率 95%,Cache 10ns,主存 100ns(缺失时先 Cache 再主存):

T_avg = 0.95×10 + 0.05×(10+100) = 9.5 + 5.5 = 15ns

例 2(多级 Cache):L1 命中 90%(1ns),L2 命中 90%(10ns),主存 100ns:

T_avg = 0.9×1 + 0.09×11 + 0.01×111 = 2.91ns

6. 提升局部性的编程技巧

循环交换(按行而非按列访问)

// 好:按行访问(空间局部性好)
for (i) for (j) A[i][j] = 0;
// 差:按列访问(空间局部性差)
for (j) for (i) A[i][j] = 0;

分块(Tiling)

for (ii = 0; ii < N; ii += B)
  for (jj = 0; jj < N; jj += B)
    for (i = ii; ...) for (j = jj; ...) 处理 A[i][j];

记忆卡片

时间 vs 空间局部性区别?
时间 = 同一数据很快再用;空间 = 附近数据很快用到。
数组 vs 链表 Cache 性能?
数组连续存储空间局部性好;链表节点分散,局部性差。
Cache 利用了哪种局部性?
两种都利用:时间→保留最近块;空间→按块加载。
平均访问时间公式?
$T_{avg} = h \times T_{hit} + (1-h) \times T_{miss}$。
矩阵乘法怎样更局部?
循环交换 + 分块,让数据留在 Cache 内。
例 2 多级 Cache 结果?
2.91ns(L1/L2/主存加权)。

交互动画 · 顺序访问 vs 跳跃访问

灰底 = 当前 Cache 块(8 个单元);橙 = 当前访问单元
点击「播放」,观察顺序访问如何留在同一 Cache 块(高命中)而跳跃访问频繁跨块(低命中)
命中 0 | 缺失 0

相关知识点

cache-memory virtual-memory

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。