页面置换算法

1.页面置换算法

  • 最优算法: OPT,理论上的算法,无法实现,是在进程执行完后进行的最佳效率计算,用来让其他算法比较差距。原理是选择未来最长时间内不被访问的页
    面置换,这样可以保证未来执行的都是马上要访问的。
  • 先进先出算法:FIFO,先调入内存的页先被置换淘汰,会产生抖动现象,即分配的页数越多,缺页率可能越多 (即效率越低)
  • 最近最少使用:LRU,在最近的过去,进程执行过程中,过去最少使用的页面被置换淘汰,根据局部性原理,这种方式效率高,且不会产生抖动现象,使用大量计数器,但是没有LFU多。
  • 淘汰原则:优先淘汰最近未访问的,而后淘汰最近未被修改的页面

你提供的内容基本准确,但有一些细节可以进一步澄清和完善。下面是对页面置换算法的系统性整理与说明:


1.1 页面置换算法概述

当物理内存不足时,操作系统需要从已加载到内存中的页面中选择一个进行淘汰(置换) ,以便为新页面腾出空间。这个选择策略就是页面置换算法


1.2 常见页面置换算法详解

1. 最优置换算法(OPT, Optimal)

  • 原理 :总是淘汰在未来最长时间内不会被访问的页面。
  • 特点
    • 理论最优,缺页率最低。
    • 不可实现,因为需要预知未来的页面访问序列。
  • 用途 :仅用于理论分析和作为其他算法性能的上限参考

✅ 正确:你提到"无法实现"、"用来让其他算法比较差距"是准确的。


2. 先进先出算法(FIFO, First-In First-Out)

  • 原理:淘汰最早进入内存的页面。
  • 实现:可用队列维护页面加载顺序。
  • 缺点
    • Belady 异常(抖动现象的一种表现):增加物理页框数量,反而导致缺页率上升。
    • 不考虑页面使用频率或近期访问情况,效率较低。

⚠️ 补充说明:"抖动(Thrashing)"通常指系统因频繁页面置换而几乎无法做有效工作,而 Belady 异常是 FIFO 特有的反直觉现象。两者相关但不完全等同。


3. 最近最少使用算法(LRU, Least Recently Used)

  • 原理 :淘汰最近最久未被使用的页面。
  • 依据 :程序的时间局部性原理(最近访问过的页面很可能再次被访问)。
  • 优点
    • 性能接近 OPT。
    • 不会出现 Belady 异常
  • 实现方式
    • 精确 LRU:需硬件支持(如时间戳或栈结构),开销大。
    • 近似 LRU:如使用引用位 + 时钟算法(Clock) 实现。

✅ 你说"效率高,且不会产生抖动现象"基本正确(更准确说是不会出现 Belady 异常)。

  • LFU(Least Frequently Used) 用计数器统计访问频率的算法。

4. 其他补充算法

时钟算法(Clock / Second-Chance)
  • FIFO 的改进版,结合引用位(reference bit)
  • 淘汰原则:优先淘汰未被访问过(R=0) 的页面;若所有页面 R=1,则全部清零再扫描。
  • 实现高效,广泛用于实际系统。
NRU(Not Recently Used)
  • 利用访问位(R)和修改位(M) 将页面分为四类,优先淘汰 R=0 且 M=0 的页面(最近未访问且未修改,写回开销小)。

✅ 你提到的"优先淘汰最近未访问的,而后淘汰最近未被修改的页面"正是 NRU 或 Clock 改进策略的思想。


1.4、关于"淘汰原则"的澄清

你写道:

"淘汰原则:优先淘汰最近未访问的,而后淘汰最近未被修改的页面"

这其实是综合考虑访问性和写回代价的策略,常见于:

  • NRU 算法
  • 改进型 Clock 算法(如 Enhanced Clock)

因为:

  • 未被修改的页面(clean page)淘汰时无需写回磁盘;
  • 已修改的页面(dirty page)需写回,开销大。

所以在访问情况相近时,优先淘汰 clean page 是合理的优化。


1.5 总结对比表

算法 是否可实现 缺页率 是否有 Belady 异常 实现复杂度 实际使用
OPT ❌ 否 最低 极高(需预知未来) 仅理论
FIFO ✅ 是 ✅ 有 少用
LRU ✅(近似) ❌ 无 高(精确)/中(近似) 广泛(近似版)
Clock/NRU ✅ 是 中低 ❌ 无 广泛(如 Linux)

这是一个非常经典且重要的操作系统概念问题。我们来一步步解释清楚:


1.6 基本概念澄清

1. 页面(Page)

  • 虚拟内存的固定大小单位(如 4KB)。
  • 程序的地址空间被划分为多个页面。
  • 页面存在于磁盘上的虚拟地址空间中,不一定在物理内存里。

2. 页框(Page Frame / Frame)

  • 物理内存中与页面大小相同的存储块。
  • 当程序需要访问某个页面时,该页面必须被加载到一个空闲的页框中。
  • 页框数量 = 物理内存大小 ÷ 页面大小。

✅ 举例:

若物理内存为 16KB,页面大小为 4KB,则系统共有 4 个页框

3. 缺页(Page Fault)

  • 当 CPU 要访问一个虚拟地址,但对应的页面不在物理内存(即没有映射到任何页框) 时,就会触发缺页异常
  • 操作系统此时必须:
    1. 找一个空闲页框(如果没有,就用页面置换算法淘汰一个页面);
    2. 从磁盘将所需页面加载到该页框;
    3. 更新页表;
    4. 重新执行被中断的指令。

❗ 缺页 ≠ 程序错误!它是虚拟内存机制的正常组成部分,但频繁缺页会严重降低性能。


二、为什么"分配更多页框,缺页率反而可能更高"?

这种现象被称为 Belady 异常(Belady's Anomaly)

✅ 关键点:

Belady 异常只出现在某些页面置换算法中(如 FIFO),而不会出现在 LRU、OPT 等"栈式算法"中。


📌 举个经典例子(FIFO 算法 + Belady 异常)

假设页面访问序列为:
1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5

情况 A:分配 3 个页框

使用 FIFO 置换:

访问 内存状态(FIFO队列) 是否缺页
1 [1]
2 [1,2]
3 [1,2,3]
4 [2,3,4] ← 淘汰1
1 [3,4,1] ← 淘汰2
2 [4,1,2] ← 淘汰3
5 [1,2,5] ← 淘汰4
1 [1,2,5]
2 [1,2,5]
3 [2,5,3] ← 淘汰1
4 [5,3,4] ← 淘汰2
5 [5,3,4]

总缺页次数:9 次


情况 B:分配 4 个页框(更多!)
访问 内存状态(FIFO) 是否缺页
1 [1]
2 [1,2]
3 [1,2,3]
4 [1,2,3,4]
1 [1,2,3,4]
2 [1,2,3,4]
5 [2,3,4,5] ← 淘汰1
1 [3,4,5,1] ← 淘汰2
2 [4,5,1,2] ← 淘汰3
3 [5,1,2,3] ← 淘汰4
4 [1,2,3,4] ← 淘汰5
5 [2,3,4,5] ← 淘汰1

总缺页次数:10 次 ❗比 3 个页框时还多!

🔍 原因:FIFO 只看"谁先进来",不看"谁将来还会用"。

多了一个页框后,本该被淘汰的"有用页面"被保留更久,反而把后面要用的页面挤出去了,导致更多缺页。


三、哪些算法会出现 Belady 异常?

算法 是否出现 Belady 异常
FIFO ✅ 会
LRU ❌ 不会
OPT ❌ 不会
Clock / NRU ❌ 通常不会(属于近似 LRU)

💡 具有"栈性质(Stack Property)"的算法(如 LRU、OPT)不会 出现 Belady 异常:

即:当页框数增加时,驻留集(resident set)是原集合的超集,不会"忘记"原来记住的页面。


四、总结

  • 页面:虚拟内存的单位。
  • 页框:物理内存中存放页面的槽位。
  • 缺页:要访问的页面不在内存中,需从磁盘调入。
  • Belady 异常 :在 FIFO 等非栈式算法 中,增加页框数反而导致缺页率上升 的反直觉现象。
  • 这也是为什么 FIFO 很少用于实际系统,而 LRU 或其近似(如 Clock)更受青睐。

🎮 简单比喻

  • 图书馆场景:

    • 页框 = 书架上的一个固定位置(只能放一本书)

    • 页面 = 一本书的内容

    • 页表 = 图书索引系统

    • 页面置换 = 书架满了,需要把某本书拿下来,换上新书

  • 你的电脑:

    • 物理内存(RAM)= 整个书架

    • 每个页框 = 书架的一格

    • 所有进程的书 = 远远超过书架容量

    • 操作系统 = 图书管理员,不断换书保证你当前看的书在书架上