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 要访问一个虚拟地址,但对应的页面不在物理内存(即没有映射到任何页框) 时,就会触发缺页异常。
- 操作系统此时必须:
- 找一个空闲页框(如果没有,就用页面置换算法淘汰一个页面);
- 从磁盘将所需页面加载到该页框;
- 更新页表;
- 重新执行被中断的指令。
❗ 缺页 ≠ 程序错误!它是虚拟内存机制的正常组成部分,但频繁缺页会严重降低性能。
二、为什么"分配更多页框,缺页率反而可能更高"?
这种现象被称为 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)= 整个书架
-
每个页框 = 书架的一格
-
所有进程的书 = 远远超过书架容量
-
操作系统 = 图书管理员,不断换书保证你当前看的书在书架上
-