2019 年第 29 题:LRU 算法、局部置换、预分配 4 个页框,访问序列 0,1,2,7,0,5,3,5,0,2,7,6,问产生页置换的总次数。
我数出来缺页 9 次,可选项最大只有 6。我以为自己数错了,连数三遍都还是 9。
最后才反应过来:这题问的是置换次数 ,不是缺页次数。
前 4 次缺页是在填空白页框 ,根本没有"换出"这个动作,不算置换。9 − 4 = 5 → 答案 C。
这两个数字一定要分清:缺页次数 9,置换次数 5。凡是题目问"置换",就要扣掉开头那些把空页框填满的次数。

〇、先花两分钟:页面置换到底在换什么
先扫盲三个词:
-
缺页(Page Fault) :要访问的页面不在内存 里,触发一次缺页中断。只要没命中,就是缺页。
-
置换(Replacement) :内存满了 还得往里放新页,就必须挑一个旧的踢出去。这个"挑一个踢出去"的动作才叫置换。
-
命中 :要访问的页面就在内存里,什么都不用做。
所以三者的关系是:
缺页次数 = 置换次数 + 开头把空页框填满的次数
判断口诀 :内存还没装满 时的缺页 → 只是"装入",不叫置换 ;内存满了之后 的缺页 → 必须"换出旧页",才叫置换。
什么时候需要置换? 请求分页系统里,进程只把一部分页面装进内存。访问时发现页不在内存(缺页),OS 就把它从外存调进来;如果此时分配给该进程的页框已经用完 ,就得先选一页换出去------选哪一页,就是页面置换算法要解决的问题。
一、四种算法,一个序列,逐个手算
下面用同一个序列 把三种经典算法走一遍(Clock 单独讲)。假设系统给进程分配 3 个页框,访问序列是:
2, 3, 2, 1, 5, 2, 4, 5, 3, 2, 5, 2
① 最佳置换算法 OPT(理想算法,实现不了)
规则 :淘汰未来最长时间不再被访问的页面(或者干脆以后都不用了的)。
它为什么"最佳" :它是开了天眼 的算法------必须预先知道后面的访问序列,实际系统做不到。它的价值是作为一个理论下限,用来评价其他算法有多差。
手算过程(内存状态按「最久未用 → 最近使用」写):
| 访问 | 2 | 3 | 2 | 1 | 5 | 2 | 4 | 5 | 3 | 2 | 5 | 2 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 内存 | 2 | 2,3 | 命中 | 2,3,1 | 2,3,5 | 命中 | 2,5,4 | 命中 | 2,5,3 | 命中 | 命中 | 命中 |
| 缺 | 缺 | 缺 | 换 1 | 换 3 | 换 4 |
→ 缺页 6 次,置换 3 次
② 先进先出 FIFO(最容易实现,也最容易出问题)
规则 :淘汰最早进入内存的那一页。就像排队,先来的先走。
| 访问 | 2 | 3 | 2 | 1 | 5 | 2 | 4 | 5 | 3 | 2 | 5 | 2 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 内存 | 2 | 2,3 | 命中 | 2,3,1 | 3,1,5 | 1,5,2 | 5,2,4 | 命中 | 2,4,3 | 命中 | 4,3,5 | 3,5,2 |
| 缺 | 缺 | 缺 | 换 2 | 换 3 | 换 1 | 换 5 | 换 2 | 换 4 |
→ 缺页 9 次,置换 6 次
注意第 5 步访问 2:2 明明刚被访问过 (第 3 步),但 FIFO 不管这个,它只看"谁先来的",照样把它换走了。这就是 FIFO 不符合程序局部性原理的地方,也是它容易产生 Belady 异常的根源。
③ 最近最久未使用 LRU(考得最多,性能最好)
规则 :淘汰最近最久没被用过 的那一页。它相信:最近用过的,待会儿大概率还会用(局部性原理)。
| 访问 | 2 | 3 | 2 | 1 | 5 | 2 | 4 | 5 | 3 | 2 | 5 | 2 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 内存 | 2 | 2,3 | 命中 | 2,3,1 | 2,1,5 | 命中 | 5,2,4 | 命中 | 4,5,3 | 5,3,2 | 命中 | 命中 |
| 缺 | 缺 | 缺 | 换 3 | 换 1 | 换 2 | 换 4 |
→ 缺页 7 次,置换 4 次
三种算法摆在一起看
| 算法 | 缺页次数 | 置换次数 | 特点 |
|---|---|---|---|
| OPT | 6 | 3 | 理论最优,实现不了,只作参照 |
| LRU | 7 | 4 | 性能好,需要硬件支持(寄存器/栈),开销大 |
| FIFO | 9 | 6 | 实现最简单,性能最差,可能 Belady 异常 |
三者的比较关系:OPT ≤ LRU ≤ FIFO(缺页次数)。记住这个不等式,选择题直接排除。
2019(29) 那道题(4 个页框、LRU、序列 0,1,2,7,0,5,3,5,0,2,7,6)完整推演:
访问 0(缺) 1(缺) 2(缺) 7(缺) → 内存满:0,1,2,7 ← 前 4 次只是装入,不算置换
访问 0 命中 → 1,2,7,0
访问 5 缺 → 淘汰 1 → 2,7,0,5 ← 置换 1
访问 3 缺 → 淘汰 2 → 7,0,5,3 ← 置换 2
访问 5 命中 → 7,0,3,5
访问 0 命中 → 7,3,5,0
访问 2 缺 → 淘汰 7 → 3,5,0,2 ← 置换 3
访问 7 缺 → 淘汰 3 → 5,0,2,7 ← 置换 4
访问 6 缺 → 淘汰 5 → 0,2,7,6 ← 置换 5
缺页 9 次,置换 5 次 → 答案 C
二、LRU 的秒杀技巧:从后往前数
2015(27) 是道"看起来要画半天表,其实十秒能出答案"的题:
4 个页框,已访问序列
2,0,2,9,3,4,2,8,2,4,8,4,5,若下一页访问 7,依据 LRU 应淘汰哪一页?
不要从头模拟。 直接从序列末尾往前数 ,数出 k 个(k = 页框数)不同的页号:
序列尾部:... 2, 4, 8, 4, 5
从后往前:5(第1个) → 4(第2个) → 8(第3个) → 2(第4个) ← 数够 4 个,停
数出的这 4 个就是此刻内存里的 4 个页 ,而其中最早数到的那个(2)就是最久没被碰过的 → 淘汰 页 2,答案 A。
原理:不管过去发生了什么,此刻内存里一定装着"最近出现过的 k 个不同页"。所以从后往前数 k 个不同页号,直接就还原了内存快照。
2025(26) 也可以用这个思路验证:3 个页框、初始已装入 0,1,2,序列 0,1,2,0,5,1,4,3,0,2,3,2,0,逐步模拟下来缺页 6 次 → 答案 B。
三、Belady 异常:页框越多,缺页反而越多
Belady 异常 :分配给进程的页框数增加 ,缺页次数不降反升。这是反直觉的,但确实会发生。
2014(30) 直接考它:可能出现 Belady 异常的是?
-
Ⅰ. LRU → ❌(LRU 是栈式算法,不会发生)
-
Ⅱ. FIFO → ✅
-
Ⅲ. OPT → ❌
→ 答案 A:仅 Ⅱ
看一个真实算例
用经典序列 1,2,3,4,1,2,5,1,2,3,4,5:
| 页框数 | FIFO 缺页次数 |
|---|---|
| 3 个 | 9 次 |
| 4 个 | 10 次 ← 页框变多,缺页反而多了一次 |
原因就是前面说的:FIFO 只看"谁先来",完全不管页面最近有没有被用过,于是可能把"马上又要访问"的页换出去,而多出来的那个页框反而改变了淘汰顺序,把情况搞得更糟。
一句话记忆 :只有 FIFO 会 Belady。LRU 和 OPT 都是"栈式算法"------页框越多,内存里装的页只会越多,缺页次数必然单调不增。
四、改进型 Clock:用两个位把页分成四类
Clock(时钟)算法 :给每页一个访问位 A ,页面排成一个环形队列。淘汰时像时钟指针一样扫,遇到 A=0 的就淘汰;遇到 A=1 就把它置 0 再跳过(给它第二次机会)。
改进型 Clock 再加一个修改位 M,一共四类(A = 访问位,M = 修改位):
2016(26) 就考淘汰次序:
| 类别 | 含义 | 淘汰优先级 |
|---|---|---|
| (0, 0) | 最近没访问过,也没修改过 | 第 1 优先淘汰(最省事,直接扔) |
| (0, 1) | 最近没访问过,但改过 | 第 2(要写回磁盘,代价大一点) |
| (1, 0) | 最近访问过,没改过 | 第 3(刚用过,可能还要用) |
| (1, 1) | 最近访问过,也改过 | 最后才考虑(又要用、又要写回) |
→ 淘汰次序 (0,0) → (0,1) → (1,0) → (1,1) ,答案 A
记忆法 :先看 A (没访问过的先走),A 相同再看 M(没改过的先走,省一次写回)。
2021(28) 把改进型 Clock 和地址变换揉在一起考:虚拟地址 02A01H、页大小 4KB、2 个固定页框。
解题分三步:
① 页大小 4KB = 2^12 B → 低 12 位是页内偏移
02A01H = 0000 0010 1010 0000 0001
低 12 位 = A01H(页内偏移,变换前后不变)
页号 = 02H
② 查页表发现 2 号页「存在位 = 0」,不在内存 → 缺页,需要置换
按改进型 Clock 从已在内存的两页里挑一页淘汰(挑中 3 号页,它占着 60H 页框)
③ 2 号页装进 60H 页框
物理地址 = 60H 拼上偏移 A01H = 60A01H
→ 答案 C:60A01H
这题的关键是页内偏移不变 :页框号从 60H 来,偏移
A01H原样搬过去,拼起来就行。
五、工作集与抖动:内存"不够用"的两种表现
工作集(2016(29))
工作集 :在时刻 t,进程最近 k 次内存访问 所访问过的页面集合(k 叫窗口大小),记作 w(k, t)。
2016(29) :窗口大小 6,序列 ..., 1,3,4,5,6,0,3,2,3,2,0,4,0,3,2,9,2,1, ...,t 时刻工作集?
取 t 时刻之前最近 6 次 访问:6, 0, 3, 2, 3, 2,去重 → {6, 0, 3, 2} → 答案 A
(注意 B 选项 {2,3,0,4} 是再往前 6 次的结果,不是"最近"的。)
抖动 / 颠簸(Thrashing)
抖动 :刚换出去的页面马上又要访问 ,于是又换别的页出去,而那个页又很快被访问......系统大部分时间都花在换页上,CPU 利用率暴跌。
根因 :分配给进程的页框数少于它当前的工作集大小。
2011(29) 问有效对策:
-
Ⅰ. 撤销部分进程 → ✅(减少并发进程数,把页框还给留下来的进程)
-
Ⅱ. 增加磁盘交换区容量 → ❌(抖动的主因不是外存不够)
-
Ⅲ. 提高用户进程优先级 → ❌(换页频率不会因为优先级而降低)
→ 答案 A:仅 Ⅰ
2022(30) 反过来问"不会影响缺页率的是":
-
A. 页面置换算法 → 会(LRU 通常低于 FIFO)
-
B. 工作集大小 → 会(工作集越大,给的页框不够就越容易缺页)
-
C. 进程数量 → 会(进程越多,每进程分到的页框越少)
-
D. 页缓冲队列长度 → 不会 (它影响的是置换的速度 ,不是缺页的次数)
→ 答案 D
2020(28) 考有效访存时间由什么决定 → 四个全要 :缺页率、磁盘读写时间、内存访问时间、执行缺页处理程序的 CPU 时间 → 答案 D。
六、易错点清单
-
把缺页次数当置换次数 → 问"置换"要扣掉开头填满空页框的次数(2019(29):9 缺页 = 5 置换)
-
从头模拟 LRU → 用"从后往前数 k 个不同页号"秒出内存快照(2015(27))
-
认为所有算法都会 Belady → 只有 FIFO(2014(30))
-
改进型 Clock 先比 M 再比 A → 反了,先看 A 再看 M(2016(26))
-
抖动时想到扩交换区 / 提优先级 → 都无效,撤销部分进程才是正解(2011(29))
-
工作集取"往前"而不是"最近" → 必须从 t 时刻往回取 k 次(2016(29))
-
认为 LRU 一定最优 → LRU 只是接近 OPT,理论上 OPT 才是下限
-
页缓冲队列影响缺页率 → 不影响,只影响置换速度(2022(30))
-
忘记页内偏移不变 → 地址变换只换页号部分,偏移原样拼接(2021(28))
-
以为页置换是系统调用 → 不是,它完全由 OS 内部完成(2021(32) 答案 C 是"创建新进程")
速查表(文末收藏版)
三种算法对比
| 算法 | 规则 | 缺页 | Belady | 备注 |
|---|---|---|---|---|
| OPT | 淘汰未来最久不用的 | 最少 | 不会 | 理论下限,实现不了 |
| LRU | 淘汰最近最久未用的 | 次少 | 不会 | 需硬件支持,开销大 |
| FIFO | 淘汰最早进来的 | 最多 | 会 | 实现最简单 |
| Clock | 环形扫描访问位 | 接近 LRU | --- | 开销小,实际系统常用 |
LRU 秒杀法
从序列末尾往前数,数出 k 个(k = 页框数)不同的页号
= 此刻内存快照;其中最早数到的那个 = 要淘汰的页
改进型 Clock 四类淘汰次序
(0,0) → (0,1) → (1,0) → (1,1) 先看访问位 A,再看修改位 M
关键数字关系
缺页次数 = 置换次数 + 开头填满空页框的次数
OPT ≤ LRU ≤ FIFO(缺页次数)
只有 FIFO 会出现 Belady 异常
抖动与工作集
抖动成因:分配的页框数 < 当前工作集大小
抖动对策:撤销部分进程(扩交换区、提优先级都无效)
工作集:t 时刻往前取 k 次访问,去重后的页面集合
不影响缺页率:页缓冲队列长度
本文依据 :王道《操作系统考研复习指导》虚拟内存管理章节;真题题干、选项与答案均逐条核对 zhenti_all.json(2009--2025 共 799 题,操作系统部分 170 题),涉及 2011(29)、2014(30)、2015(27)(30)、2016(26)(29)、2019(29)、2020(28)、2021(28)(32)、2022(29)(30)、2025(26)(27)。文中三种算法的对比演算(序列 2,3,2,1,5,2,4,5,3,2,5,2)与 Belady 算例(序列 1,2,3,4,1,2,5,1,2,3,4,5)均为本文自行推演,与算法定义一致。