3.2.4 页面置换算法

1.最佳置换算法

最佳置换算法(Optimal Replacement Algorithm,简称 OPT 或 Belady 算法) 是一种理论上的操作系统页面置换算法。它的核心思想是:每次置换时,选择以后永不使用,或者在最长时间内不再被访问的页面进行淘汰。

它是所有页面置换算法中性能最好的,因为它能保证获得最低的缺页率。


1. 核心逻辑

当进程请求的页面不在内存中(缺页),且物理块(Frames)已满时:

  1. 观察该时刻之后的所有页面引用序列。
  2. 找出当前内存中哪些页面在未来还会被使用。
  3. 找到那个在最远的将来才会被访问(或者根本不再访问)的页面。
  4. 将其换出。

2. 实例演示

假设系统分配了 3个物理块,页面引用序列为:7, 0, 1, 2, 0, 3, 0, 4, 2

步骤引用页面内存状态 (3个块)是否缺页备注
17[7, , ]调入 7
20[7, 0, ]调入 0
31[7, 0, 1]调入 1
42[2, 0, 1]替换 7。因为未来序列中 0 和 1 很快会出现,而 7 永不出现。
50[2, 0, 1]命中
63[2, 0, 3]替换 1。未来序列中 0 和 2 都会用到,1 不再用到。
70[2, 0, 3]命中
84[4, 0, 3]替换 2。2 在最后才出现,比 0 和 3 更晚(或不再出现)。

3. 算法特点

优点

  • 最低缺页率:在相同物理块数量下,没有任何算法的缺页次数能少于 OPT。
  • 无 Belady 异常:随着物理块的增加,缺页率一定会降低或保持不变,不会出现反常现象。

缺点(致命伤)

  • 无法实现:操作系统无法预知未来。就像人类无法准确预知股票走势一样,内核无法提前知道进程下一个要访问的具体页面。

4. 为什么还要研究它?

既然无法实现,OPT 算法存在的意义主要有两个:

  1. 作为衡量标准(Benchmark):在实验室环境下,通过先运行一遍程序记录下所有访问序列,再用 OPT 计算出理想状态下的最低缺页率。然后将其他实际算法(如 LRU、FIFO)的效果与之对比,衡量这些算法的优劣。
  2. 理论指导:它告诉我们,页面置换的效率取决于对“未来”预测的准确性。

5. 与 LRU 的对比

  • OPT(最佳):向看(未来),选择最晚使用的。
  • LRU(最近最久未使用):向看(过去),选择最久没用的。

提示:由于“局部性原理”,LRU 算法被认为是 OPT 算法在实际应用中的最佳近似。

2.先进先出页面置换算法

先进先出置换算法(First-In, First-Out, 简称 FIFO) 是最简单、最直观的一种页面置换算法。

它的核心思想是:总是淘汰最先进入内存的页面,即选择在内存中驻留时间最长的页面进行替换。这种算法假设先进入内存的页面,其不再被访问的可能性最大。


1. 核心逻辑

FIFO 算法在管理内存时,通常维护一个队列

  1. 调入页面:当一个新页面被调入内存时,将其插入队列的末尾。
  2. 置换页面:当内存空间已满且需要调进新页面时,选择队列头部(最老的)的页面将其换出,新页面排在队尾。

2. 实例演示

假设系统分配了 3个物理块,页面引用序列为:7, 0, 1, 2, 0, 3, 0

步骤引用页面内存状态 (队头 → 队尾)是否缺页备注
17[7]7 进入
20[7, 0]0 进入
31[7, 0, 1]1 进入
42[0, 1, 2]替换 7(7 是最老的)
50[1, 2, 0]替换 0(虽然 0 刚被引用,但它在内存里最久)
63[2, 0, 3]替换 1
70[2, 0, 3]命中

注意:在第 5 步中,尽管 0 经常被访问,但 FIFO 依然会因为它“进入得早”而将其踢出,这体现了该算法的局限性。


3. Belady 异常 (Belady’s Anomaly)

FIFO 算法有一个非常出名的缺陷,称为 Belady 异常

通常情况下,我们会认为增加物理块(内存容量)会降低缺页率。但在使用 FIFO 算法时,可能会出现:物理块数增加,缺页次数反而增多的反常现象。

  • 原因:FIFO 只考虑进入时间,完全忽视了页面访问的热度或频率。
  • 对比:最佳置换算法(OPT)和最近最久未使用算法(LRU)永远不会出现这种异常。

4. 算法评价

优点

  • 简单易行:实现成本极低,只需要一个简单的先进先出队列。
  • 开销小:不需要像 LRU 那样频繁地更新硬件寄存器或复杂的链表顺序。

缺点

  • 性能较差:缺页率通常较高。
  • 不切实际:它不考虑页面的访问频率。例如,一个包含循环、常驻变量或全局变量的页面可能会被频繁访问,但如果它进入内存较早,FIFO 也会毫不留情地将其换出,导致频繁缺页。

5. 总结对比

特性OPT (最佳)FIFO (先进先出)LRU (最近最久未使用)
置换依据未来最久不用的进入内存最久的过去最久没用的
性能最好最差较好(接近 OPT)
实现可行性无法实现易于实现可实现(需硬件支持)
Belady 异常

3.LRU页面置换算法

最近最久未使用置换算法(Least Recently Used, 简称 LRU) 是操作系统内存管理中最常用、最有效的页面置换算法之一。

它的核心思想是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。 因此,当内存空间不足时,LRU 选择淘汰那个过去最长时间未被使用的页面。


1. 核心原理

LRU 实际上是“向前看”的算法。它利用了程序运行的局部性原理(Temporal Locality):

  • 它认为刚被访问过的页面,很快可能再次被访问。
  • 它认为很久没被访问的页面,可能在未来较长时间内也不会被访问。

2. 实例演示

假设系统分配了 3个物理块,页面引用序列为:1, 2, 3, 4, 1, 2, 5

步骤引用页面内存状态 (最近使用 → 最久未使用)是否缺页备注
11[1]1 进入
22[2, 1]2 进入,1 变为最久未使用
33[3, 2, 1]3 进入,1 准备被淘汰
44[4, 3, 2]替换 1(1 是最久没用的)
51[1, 4, 3]替换 2(2 是最久没用的)
62[2, 1, 4]替换 3(3 是最久没用的)
75[5, 2, 1]替换 4(4 是最久没用的)

注意: 如果在步骤 7 之前再次访问了 1,那么 1 会被移动到“最近使用”的位置,而不会被淘汰。


3. 如何实现 LRU?

在实际系统中,由于每次内存访问都要更新记录,LRU 的硬件开销较大。主要有两种常见的实现方式:

  1. 计数器 (Counters)
    • 为每个页面表项关联一个“使用时间”字段。
    • 每次页面被引用时,将当前时钟值写入该字段。
    • 置换时,查找时间戳最小的页面。
  2. 栈 (Stack)
    • 维护一个页面号的栈。
    • 每当访问一个页面,就将其从栈中抽出并压入栈顶。
    • 栈底永远是“最久未使用”的页面。

4. 算法评价

优点

  • 性能优异:非常接近理想的最佳置换算法(OPT)。
  • 无 Belady 异常:LRU 属于“栈式算法”,增加物理块数量绝不会导致缺页率上升。
  • 适应性强:能够很好地处理具有良好局部性的程序。

缺点

  • 开销大:需要频繁更新内存状态(时间戳或栈位置),如果没有特殊的硬件支持,纯软件实现会显著降低系统性能。
  • 并非完全理想:对于某些特定模式(如大面积扫描整个数组),LRU 可能会失效。

4.CLOCK算法

1.简单CLOCK算法

简单 CLOCK 算法(Simple Clock Algorithm),又称为最近未使用算法(NRU, Not Recently Used)*或*二次机会算法(Second Chance Algorithm)

它是对 LRU 算法的一种廉价近似。因为 LRU 硬件开销太大(需要复杂的栈或时间戳),CLOCK 算法通过一个“访问位”“循环队列”,以极低的成本实现了类似 LRU 的效果。


1. 核心机制

CLOCK 算法将内存中的所有页面保存在一个循环链表中,并用一个指针(像钟表的指针一样)指向其中一个页面。

每个页面都有一个访问位(Reference Bit)

  • 1:表示该页面最近被访问过。
  • 0:表示该页面最近未被访问过。

2. 运行过程

场景 A:页面被访问(命中)

当进程访问内存中已有的页面时,操作系统只需将该页面的访问位设为 1。这个操作非常快,几乎没有开销。

场景 B:页面缺页(置换)

当需要换出页面时,指针开始“转动”检查:

  1. 检查当前页面
    • 如果访问位是 0:说明它最近没被用过,直接将其换出,新页面换入,访问位置 1,指针下移。
    • 如果访问位是 1:说明它最近用过,算法给它“第二次机会”——将其置为 0,指针移向下一个页面继续检查。
  2. 重复执行:如果所有页面的访问位都是 1,指针转完一圈后会将所有位都清零,最终会回到起点换出第一个页面。

3. 实例演示

假设有 3 个物理块,页面顺序:1, 2, 3, 4

  1. 加载 1, 2, 3:内存填满,访问位均为 [1, 1, 1],指针指向 1。
  2. 访问 4(缺页)
    • 检查 1:位是 1 \rightarrow 变 0,指针移到 2。
    • 检查 2:位是 1 \rightarrow 变 0,指针移到 3。
    • 检查 3:位是 1 \rightarrow 变 0,指针移回 1。
    • 再次检查 1:此时位是 0 \rightarrow 替换 1,存入 4,位设为 1,指针移到 2。

4. 为什么叫“二次机会”?

这个算法的名字非常形象:如果一个页面被访问过,它的访问位就是 1。当指针第一次经过它时,它不会被踢走,而是得到一次“豁免权”,代价是访问位清零。只有当指针转了一圈回来它还没被访问,它才会被换出。


5. 简单 CLOCK vs. LRU

特性LRU (最近最久未使用)简单 CLOCK (二次机会)
精确度绝对精确地找最久没用的粗略地找最近没用的
性能极高接近 LRU
硬件开销很大(需记录访问顺序)很小(只需 1 个位)
操作复杂度每次访问都要更新记录访问只改 1 位,置换时才扫描

6. 算法评价

  • 优点:实现极其简单,性能远好于 FIFO,且避免了 LRU 昂贵的硬件实现代价。
  • 缺点:在极端情况下(例如所有位都是 1),它会退化成 FIFO 算法。

2.改进型CLOCK算法

改进型 CLOCK 算法(Improved Clock Algorithm)在简单 CLOCK 算法的基础上增加了一个维度:修改位(Modified Bit,又称 Dirty Bit)

1. 为什么要改进?

在简单 CLOCK 算法中,只考虑了页面是否被“访问”过。但实际上,内存中的页面有两种状态:

  • 未修改过(Clean):内存内容与磁盘一致。换出时直接覆盖即可,不需要磁盘 I/O。
  • 修改过(Dirty):内存内容已被更新。换出时必须写回磁盘,这涉及昂贵的磁盘 I/O 操作。

核心思想:如果能优先换出“未修改过”的页面,就可以减少磁盘 I/O 的次数,从而提高系统性能。


2. 两个状态位

每个页面现在由一对坐标表示 (访问位 A, 修改位 M)

  • A (Access):1 表示最近访问过,0 表示未访问。
  • M (Modified):1 表示被修改过,0 表示未修改。

基于这两个位,页面可以分为四类(优先级从高到低):

  1. 第 1 类 (0, 0):最近未访问,且未修改。—— 最佳换出对象(开销最小)。
  2. 第 2 类 (0, 1):最近未访问,但被修改过。—— 换出它需要写回磁盘,但由于最近没用过,适合置换。
  3. 第 3 类 (1, 0):最近访问过,但未修改。—— 可能很快还会被用。
  4. 第 4 类 (1, 1):最近访问过,且修改过。—— 最不该置换的对象

3. 算法运行步骤(四轮扫描)

改进型 CLOCK 算法的指针转动逻辑比简单版本复杂,它最多可能扫描四轮:

  • 第一轮扫描:寻找 (0, 0)
    • 指针转动,不做任何修改。如果找到 (0, 0),直接换出。
  • 第二轮扫描:寻找 (0, 1)
    • 如果第一轮没找到,开始第二轮。寻找 (0, 1) 的页面。
    • 注意:在这一轮经过的所有页面,将其访问位 A 置为 0
    • 如果找到第一个 (0, 1),将其换出。
  • 第三轮扫描:再次寻找 (0, 0)
    • 如果第二轮还没找到,此时由于所有页面的 A 位都已被清零,内存中肯定存在 (0, 0) 或 (0, 1)。
    • 重复第一轮的动作,寻找 (0, 0)。
  • 第四轮扫描:再次寻找 (0, 1)
    • 如果第三轮还没找到,寻找 (0, 1) 并换出。

4. 实例直观理解

想象时钟指针转动:

  1. 它先找那些既没用过又干净的页面(最省事)。
  2. 找不到的话,它找没用过但脏了的页面(虽然要写磁盘,但反正没人用)。在找的过程中,把路过的页面的“访问勋章”给摘了(A置0)。
  3. 如果还是没找到,就回过头再找那些刚刚被摘了勋章、变干净的页面。

5. 算法对比

特性简单 CLOCK改进型 CLOCK
考虑因素只看访问位 (A)访问位 (A) + 修改位 (M)
磁盘 I/O较多(可能频繁换出脏页)显著减少(优先换出干净页)
算法复杂度低(转一圈肯定能找到)较高(最多转两圈/四次扫描)
性能较好更好(现代操作系统的常用选择)

6. 总结

改进型 CLOCK 算法体现了操作系统设计中的一个重要权衡:用稍微复杂一点的软件逻辑(多扫描几轮内存),来换取昂贵的硬件操作(磁盘 I/O)的减少。

这种“宁可多绕路,不可多写盘”的策略,是系统性能优化的经典思维。

5.对比

1. 页面置换算法“避坑”口诀

OPT 像预知:掐指一算看未来,最远不用先拜拜。(最好用,难实现

FIFO 像排队:先入为主排在前,管你多忙也滚蛋。(最简单,有异常

LRU 像翻旧账:往事如烟看过去,谁最久远谁离场。(最常用,代价大

CLOCK 像给机会:时钟转转看标志,二次机会再续命。(最平衡,看位子

改进 CLOCK 像省钱:不仅看你用没用,还看写没写磁盘。(最省力,少写盘


2. 四大算法核心参数对比

算法英文简称核心逻辑优缺点关键词
最佳置换OPT淘汰将来最久不用的理论最高分,但现实中“无法预知未来”标杆/参考
先进先出FIFO淘汰最早进入内存的简单但性能差,有 Belady 异常排队/队列
最近最久未使用LRU淘汰过去最久不用的性能极佳(接近 OPT),但硬件成本高局部性/栈
时钟置换CLOCK淘汰最近未被访问的LRU 的“廉价版”,平衡了性能与开销访问位/循环
改进型时钟N/A优先淘汰未访问+未修改减少了磁盘写回操作,进一步提升效率修改位/省 IO

3. 一个直观的选型建议

在实际的面试或考试中,这几个算法的出场率极高,理解逻辑比背公式更重要:

  • 考试追求高分? 请牢记 LRU。它是面试和笔试中最常考的,重点在于“向前看”。
  • 面试考深度? 准备好解释 Belady 异常(为什么内存大了缺页反而多)以及 CLOCK 算法 如何用一个 bit 位模拟 LRU。
  • 设计高性能系统? 优先考虑 改进型 CLOCK,因为磁盘写入(Dirty Bit)永远是计算机系统的性能瓶颈。

发表评论