Appearance
题目
现有一 LRU 算法,采用固定分配局部置换的页面置换策略,已为进程分配 3 个页框,页面访问序列为 {0,1,2,0,5,1,4,3,0,2,3,2,0},其中 0,1,2 已调入内存。则缺页次数是( )。
错因
A
漏算了一次缺页。最常见漏的是最后阶段访问 2 那次——因为访问序列里前面已经出现过 2,下意识以为它"还在内存",但 2 在中间已经被替换出去了,再访问要重新调入,是缺页。 个访问位置里只要漏看一次"已被替换"的页面,就会少算 1 次。
C
把"已调入页面也算缺页"误算进去了。题目明确说"0,1,2 已调入内存"——最开始访问 0、1、2 时是命中,不算缺页。如果把这 3 次也按"首次访问算缺页"凑进去( 或类似算法),就会得到 7。
D
LRU 替换原则没记牢,把 LRU 当成 FIFO 用了。FIFO 严格按"调入先后"踢人,会比 LRU 多踢几次"还热"的页;而且本题中访问序列尾部 0、2、3 反复出现,LRU 能把它们留下,FIFO 不行。 这个数往往出现在用 FIFO 重做这道题的人手里。
总解析
LRU 核心规则:缺页时,替换"最久未被访问"的页。命中也要更新——刚被访问的页变成"最近最新"。
记法:用一个长度为 3 的"最近使用栈",栈顶 = 最新访问,栈底 = 最久未访问。每次访问:
- 命中:把该页移到栈顶
- 缺页:踢掉栈底,新页进栈顶
逐步推演(13 次访问):
| 第 # 次 | 访问页 | 操作 | 缺页栈(栈底→栈顶) | 是否缺页 |
|---|---|---|---|---|
| 初始 | — | 已调入 0,1,2 | [0, 1, 2] | — |
| 1 | 0 | 命中,0 提到栈顶 | [1, 2, 0] | 否 |
| 2 | 1 | 命中,1 提到栈顶 | [2, 0, 1] | 否 |
| 3 | 2 | 命中,2 提到栈顶 | [0, 1, 2] | 否 |
| 4 | 0 | 命中,0 提到栈顶 | [1, 2, 0] | 否 |
| 5 | 5 | 缺页,踢栈底 1 | [2, 0, 5] | ✓ ① |
| 6 | 1 | 缺页,踢栈底 2 | [0, 5, 1] | ✓ ② |
| 7 | 4 | 缺页,踢栈底 0 | [5, 1, 4] | ✓ ③ |
| 8 | 3 | 缺页,踢栈底 5 | [1, 4, 3] | ✓ ④ |
| 9 | 0 | 缺页,踢栈底 1 | [4, 3, 0] | ✓ ⑤ |
| 10 | 2 | 缺页,踢栈底 4 | [3, 0, 2] | ✓ ⑥ |
| 11 | 3 | 命中,3 提到栈顶 | [0, 2, 3] | 否 |
| 12 | 2 | 命中,2 提到栈顶 | [0, 3, 2] | 否 |
| 13 | 0 | 命中,0 提到栈顶 | [3, 2, 0] | 否 |
数一下打勾:5、6、7、8、9、10 这 6 次缺页。
易错点提醒:
- 第 9 步访问 0 时——0 在第 7 步被踢出了,再访问要重新调入,是缺页。同理第 10 步的 2 在第 6 步已被踢。回头看序列里"早期出现过的页"不能默认它还在,必须看当前内存状态。
- 第 11~13 次访问 3、2、0 全部命中——它们刚分别在第 8、10、9 步被调入,正"热"。
最终答案是 B(6 次缺页)。