操作系统计算题专项练习(15题)


段页计算只需要做11 12 14三道,13 15不要求掌握

1. 银行家算法

题目内容
某系统使用银行家算法避免死锁。当前系统资源情况如下:

  • 可用资源向量 Available = (3, 3, 2)
  • 系统中有 5 个进程 P0~P4,3 种资源 A(共 10 个)、B(共 5 个)、C(共 7 个)

各进程的 Allocation(已分配)和 Max(最大需求)矩阵如下:

进程 Allocation (A, B, C) Max (A, B, C)
P0 (0, 1, 0) (7, 5, 3)
P1 (2, 0, 0) (3, 2, 2)
P2 (3, 0, 2) (9, 0, 2)
P3 (2, 1, 1) (2, 2, 2)
P4 (0, 0, 2) (4, 3, 3)

请回答:

  1. 当前系统是否处于安全状态?如果安全,给出一个安全序列。
  2. 如果进程 P1 发出请求 Request₁ = (1, 0, 2),系统能否将资源分配给它?为什么?

考点:银行家算法的安全性检查和资源请求判定

来源章节:第 8 章 — 死锁与银行家算法

完整解答过程

步骤1:计算 Need 矩阵
Need[i] = Max[i] - Allocation[i]

进程 Need (A, B, C)
P0 (7, 4, 3)
P1 (1, 2, 2)
P2 (6, 0, 0)
P3 (0, 1, 1)
P4 (4, 3, 1)

步骤2:安全性检查
Available = (3, 3, 2)

轮次 Work(当前可用) 可满足的进程 原因
第1轮 (3, 3, 2) P1: Need(1,2,2) ≤ Work(3,3,2) ✓ P1 的 Need 均 ≤ Work
P3: Need(0,1,1) ≤ Work(3,3,2) ✓ P3 也可满足,选择任一均可
选 P1 Finish[P1]=True Work = (3,3,2)+(2,0,0) = (5,3,2) 释放 P1 的 Allocation
第2轮 (5, 3, 2) P3: Need(0,1,1) ≤ (5,3,2) ✓
选 P3 Finish[P3]=True Work = (5,3,2)+(2,1,1) = (7,4,3)
第3轮 (7, 4, 3) P0: Need(7,4,3) ≤ (7,4,3) ✓
P4: Need(4,3,1) ≤ (7,4,3) ✓
P2: Need(6,0,0) ≤ (7,4,3) ✓
选 P0 Finish[P0]=True Work = (7,4,3)+(0,1,0) = (7,5,3)
第4轮 (7, 5, 3) P2: Need(6,0,0) ≤ (7,5,3) ✓
P4: Need(4,3,1) ≤ (7,5,3) ✓
选 P2 Finish[P2]=True Work = (7,5,3)+(3,0,2) = (10,5,5)
第5轮 (10, 5, 5) P4: Need(4,3,1) ≤ (10,5,5) ✓
选 P4 Finish[P4]=True Work = (10,5,5)+(0,0,2) = (10,5,7)

所有 Finish[i] = True,存在安全序列 <P1, P3, P0, P2, P4>。

答(第1问):系统当前处于安全状态,一个安全序列为 <P1, P3, P0, P2, P4>(注意安全序列不唯一)。

步骤3:判断 P1 的请求 Request₁ = (1, 0, 2)

(1) Request₁(1,0,2) ≤ Need₁(1,2,2) ✓
(2) Request₁(1,0,2) ≤ Available(3,3,2) ✓
(3) 尝试分配,更新状态:
- Available’ = (3,3,2) - (1,0,2) = (2,3,0)
- Allocation₁’ = (2,0,0) + (1,0,2) = (3,0,2)
- Need₁’ = (1,2,2) - (1,0,2) = (0,2,0)

步骤4:对新状态进行安全性检查

进程 Allocation’ Need’
P0 (0, 1, 0) (7, 4, 3)
P1 (3, 0, 2) (0, 2, 0)
P2 (3, 0, 2) (6, 0, 0)
P3 (2, 1, 1) (0, 1, 1)
P4 (0, 0, 2) (4, 3, 1)

Work = Available’ = (2, 3, 0)

轮次 Work 可满足进程
第1轮 (2, 3, 0) P1: Need(0,2,0) ≤ (2,3,0) ✓
选P1后 (2,3,0)+(3,0,2) = (5,3,2)
第2轮 (5, 3, 2) P3: Need(0,1,1) ≤ (5,3,2) ✓
选P3后 (5,3,2)+(2,1,1) = (7,4,3)
第3轮 (7, 4, 3) P0: Need(7,4,3) ≤ (7,4,3) ✓
选P0后 (7,4,3)+(0,1,0) = (7,5,3)
第4轮 (7, 5, 3) P2: Need(6,0,0) ≤ (7,5,3) ✓
选P2后 (7,5,3)+(3,0,2) = (10,5,5)
第5轮 (10, 5, 5) P4: Need(4,3,1) ≤ (10,5,5) ✓
选P4后 (10,5,5)+(0,0,2) = (10,5,7)

新状态仍然安全,安全序列 <P1, P3, P0, P2, P4>。

答(第2问):可以分配,分配后系统仍处于安全状态。


2. 分段地址转换

题目内容
某系统采用分段存储管理,段表如下所示。请将以下逻辑地址转换为物理地址。

段表

段号 段长 基址
0 600 2100
1 200 3500
2 500 1200
3 800 6800

逻辑地址(段号, 段内偏移):

  1. (0, 250)
  2. (1, 150)
  3. (2, 600)
  4. (3, 400)

考点:分段地址转换的原理与越界检查

来源章节:第 5 章 — 内存管理之分段存储

完整解答过程

基本公式:物理地址 = 段基址 + 段内偏移
条件:段内偏移必须 < 段长,否则产生"越界中断"。

  1. 逻辑地址 (0, 250)

    • 段号 0:段长 = 600,基址 = 2100
    • 检查越界:250 < 600 ✓
    • 物理地址 = 2100 + 250 = 2350
    • :(0, 250) → 物理地址 2350
  2. 逻辑地址 (1, 150)

    • 段号 1:段长 = 200,基址 = 3500
    • 检查越界:150 < 200 ✓
    • 物理地址 = 3500 + 150 = 3650
    • :(1, 150) → 物理地址 3650
  3. 逻辑地址 (2, 600)

    • 段号 2:段长 = 500,基址 = 1200
    • 检查越界:600 ≥ 500 ✗ —— 越界!
    • :(2, 600) 段内偏移越界,产生段越界中断,无法转换。
  4. 逻辑地址 (3, 400)

    • 段号 3:段长 = 800,基址 = 6800
    • 检查越界:400 < 800 ✓
    • 物理地址 = 6800 + 400 = 7200
    • :(3, 400) → 物理地址 7200

3. 分页地址转换

题目内容
某系统采用分页存储管理,页面大小为 4KB(4096 字节)。已知某进程的页表如下:

逻辑页号 物理帧号
0 3
1 7
2 1
3 5
4 8
5 2

请将以下虚拟地址转换为物理地址:

  1. 虚拟地址 0x2A3C
  2. 虚拟地址 0x1120
  3. 虚拟地址 0x54A8

考点:分页地址转换、页号与页内偏移的提取

来源章节:第 5 章 — 内存管理之分页存储

完整解答过程

已知条件

  • 页面大小 = 4KB = 4096B = 2¹²,页内偏移占 12 位
  • 逻辑地址中:高 20 位为页号,低 12 位为页内偏移

步骤

  1. 将十六进制地址转为二进制或直接计算:页号 = 地址 / 4096(整除),偏移 = 地址 % 4096

1. 虚拟地址 0x2A3C

  • 0x2A3C = 10812(十进制)
  • 页号 = 10812 ÷ 4096 = 2(商)
  • 偏移 = 10812 % 4096 = 10812 - 2×4096 = 10812 - 8192 = 2620 = 0xA3C
  • 查页表:页号 2 → 物理帧号 1
  • 物理地址 = 帧号 × 4096 + 偏移 = 1 × 4096 + 2620 = 6716 = 0x1A3C
  • :0x2A3C → 物理地址 0x1A3C(6716)

2. 虚拟地址 0x1120

  • 0x1120 = 4384(十进制)
  • 页号 = 4384 ÷ 4096 = 1
  • 偏移 = 4384 % 4096 = 288 = 0x120
  • 查页表:页号 1 → 物理帧号 7
  • 物理地址 = 7 × 4096 + 288 = 28672 + 288 = 28960 = 0x7120
  • :0x1120 → 物理地址 0x7120(28960)

3. 虚拟地址 0x54A8

  • 0x54A8 = 21672(十进制)
  • 页号 = 21672 ÷ 4096 = 5
  • 偏移 = 21672 % 4096 = 21672 - 5×4096 = 21672 - 20480 = 1192 = 0x4A8
  • 查页表:页号 5 → 物理帧号 2
  • 物理地址 = 2 × 4096 + 1192 = 8192 + 1192 = 9384 = 0x24A8
  • :0x54A8 → 物理地址 0x24A8(9384)

【扩展】二级页表计算

假设某系统有 32 位虚拟地址,页面大小 4KB,页表项大小 4B。

  • 页内偏移 = 12 位(2¹² = 4KB)
  • 剩余 20 位用于页号
  • 若采用一级页表:页表大小为 2²⁰ × 4B = 4MB(过大)
  • 若采用二级页表:将 20 位页号分为 10 位一级页号 + 10 位二级页号
    • 一级页表大小 = 2¹⁰ × 4B = 4KB
    • 每个二级页表大小 = 2¹⁰ × 4B = 4KB
    • 地址转换:虚拟地址 → 一级页号 → 查一级页表得二级页表基址 → 二级页号 → 查二级页表得物理帧号 → 拼接偏移得物理地址

4. FCFS / SJF / HRRN 调度算法

题目内容
考虑下列一组进程,所有时间单位为毫秒:

进程 到达时间 执行时间(CPU突发时间)
P1 0 8
P2 1 4
P3 2 9
P4 3 5

请分别使用以下算法计算每个进程的周转时间等待时间平均周转时间,并画出甘特图:

  1. FCFS(先来先服务)
  2. SJF(非抢占式短作业优先)
  3. HRRN(最高响应比优先)

考点:调度算法的性能比较(周转时间、等待时间)

来源章节:第 4 章 — 处理器调度

完整解答过程

(1) FCFS(先来先服务)

按到达时间顺序调度:P1 → P2 → P3 → P4

甘特图

P1        P2    P3              P4
|---------|-----|---------------|-----|
0         8     12              21    26

计算过程

进程 到达 执行 开始 完成 周转时间(TAT) 等待时间
P1 0 8 0 8 8-0 = 8 0
P2 1 4 8 12 12-1 = 11 8-1 = 7
P3 2 9 12 21 21-2 = 19 12-2 = 10
P4 3 5 21 26 26-3 = 23 21-3 = 18

平均周转时间 = (8 + 11 + 19 + 23) / 4 = 61 / 4 = 15.25 ms
平均等待时间 = (0 + 7 + 10 + 18) / 4 = 35 / 4 = 8.75 ms

(2) SJF(非抢占式短作业优先)

执行顺序判断

  • 时刻 0:只有 P1 已到达,执行 P1(0~8)
  • 时刻 8:P2、P3、P4 均已到达,比较执行时间:P2(4) < P4(5) < P3(9)
  • 执行顺序:P1 → P2 → P4 → P3

甘特图

P1        P2    P4    P3
|---------|-----|-----|---------------|
0         8     12    17              26

计算过程

进程 到达 执行 开始 完成 周转时间 等待时间
P1 0 8 0 8 8 0
P2 1 4 8 12 11 7
P4 3 5 12 17 14 9
P3 2 9 17 26 24 15

平均周转时间 = (8 + 11 + 14 + 24) / 4 = 57 / 4 = 14.25 ms
平均等待时间 = (0 + 7 + 9 + 15) / 4 = 31 / 4 = 7.75 ms

(3) HRRN(最高响应比优先)

响应比公式:R = (等待时间 + 执行时间) / 执行时间 = 1 + 等待时间 / 执行时间

  • 时刻 0:只有 P1,执行 P1(0~8)
  • 时刻 8:计算等待进程的响应比
    • P2:R = 1 + (8-1)/4 = 1 + 7/4 = 2.75
    • P3:R = 1 + (8-2)/9 = 1 + 6/9 = 1.67
    • P4:R = 1 + (8-3)/5 = 1 + 5/5 = 2.00
    • P2 的响应比最高(2.75),执行 P2(8~12)
  • 时刻 12:计算剩余进程的响应比
    • P3:R = 1 + (12-2)/9 = 1 + 10/9 = 2.11
    • P4:R = 1 + (12-3)/5 = 1 + 9/5 = 2.80
    • P4 的响应比最高(2.80),执行 P4(12~17)
  • 时刻 17:只剩 P3,执行 P3(17~26)

甘特图

P1        P2    P4    P3
|---------|-----|-----|---------------|
0         8     12    17              26

计算过程

进程 到达 执行 开始 完成 周转时间 等待时间
P1 0 8 0 8 8 0
P2 1 4 8 12 11 7
P4 3 5 12 17 14 9
P3 2 9 17 26 24 15

平均周转时间 = (8 + 11 + 14 + 24) / 4 = 14.25 ms
平均等待时间 = (0 + 7 + 9 + 15) / 4 = 7.75 ms

注意:在本例中 HRRN 和 SJF 的结果相同,这是因为在时刻 8 时 P2 既是执行时间最短的也是响应比最高的。HRRN 的优势在进程执行时间差异大、等待时间差异大时更能体现。


5. RR 时间片轮转调度

题目内容
考虑下列一组进程,使用时间片轮转(Round-Robin)调度算法,时间片 q = 3 ms。

进程 到达时间 执行时间(CPU突发时间)
P1 0 5
P2 1 3
P3 2 8
P4 4 2

请计算每个进程的完成时间周转时间等待时间,并画出调度甘特图。

考点:RR 时间片轮转调度的执行过程分析

来源章节:第 4 章 — 处理器调度

完整解答过程

规则:就绪队列按到达时间排队,先到的先入队。每个进程运行一个时间片(最多 3 ms),若执行完毕则退出,否则放回队尾。

分步追踪

就绪队列初始为空,用 [ ] 表示队列状态(左侧为队头)。

  • t=0:P1 到达,就绪队列:[P1(剩余5)]。调度 P1。
  • t=0~3:P1 运行 3 ms,剩余 2 ms。t=1时P2到达入队,t=2时P3到达入队。
    • P1 时间片用完,放回队尾。就绪队列:[P2(3), P3(8), P1(2)]
  • t=3~6:调度 P2,运行 3 ms,剩余 0 ms。P2 执行完毕。
    • t=4时P4到达,入队。就绪队列:[P3(8), P1(2), P4(2)]
  • t=6~9:调度 P3,运行 3 ms,剩余 5 ms。时间片用完放回队尾。就绪队列:[P1(2), P4(2), P3(5)]
  • t=9~11:调度 P1,运行 2 ms,剩余 0 ms。P1 执行完毕。
    • 就绪队列:[P4(2), P3(5)]
  • t=11~13:调度 P4,运行 2 ms,剩余 0 ms。P4 执行完毕。
    • 就绪队列:[P3(5)]
  • t=13~16:调度 P3,运行 3 ms,剩余 2 ms。时间片用完放回队尾。就绪队列:[P3(2)]
  • t=16~18:调度 P3,运行 2 ms,剩余 0 ms。P3 执行完毕。

甘特图

P1    P2    P3    P1    P4    P3    P3
|-----|-----|-----|-----|-----|-----|-----|
0     3     6     9     11    13    16    18

结果汇总

进程 到达时间 完成时间 周转时间 等待时间
P1 0 11 11 11-5 = 6
P2 1 6 5 5-3 = 2
P3 2 18 16 16-8 = 8
P4 4 13 9 9-2 = 7

计算说明

  • 周转时间 = 完成时间 - 到达时间
  • 等待时间 = 周转时间 - 执行时间

平均周转时间 = (11 + 5 + 16 + 9) / 4 = 41 / 4 = 10.25 ms
平均等待时间 = (6 + 2 + 8 + 7) / 4 = 23 / 4 = 5.75 ms


6. 内存分配算法(动态分区分配)

题目内容
某系统采用动态分区分配方式管理内存,内存大小为 1024 KB。当前空闲分区链中有以下空闲分区(按地址从小到大排列):

分区 起始地址 大小
空闲1 0 50 KB
空闲2 100 200 KB
空闲3 500 80 KB
空闲4 800 150 KB
空闲5 1000 24 KB

进程请求分配内存,请求序列如下(按顺序):

  1. 请求 A:120 KB
  2. 请求 B:50 KB
  3. 请求 C:90 KB
  4. 请求 D:30 KB

请分别使用 首次适应(First-Fit)最佳适应(Best-Fit)最差适应(Worst-Fit) 算法,说明每个请求分配到哪个空闲分区,并给出每次分配后的空闲分区列表。如果不能分配,请说明原因。

考点:动态分区分配算法(First-Fit、Best-Fit、Worst-Fit)

来源章节:第 5 章 — 内存管理之动态分区分配

完整解答过程

(1) 首次适应算法(First-Fit)

按地址顺序查找第一个足够大的空闲分区。

初始空闲列表:[50(0), 200(100), 80(500), 150(800), 24(1000)]
(格式:大小KB(起始地址))

① 请求 A:120 KB

  • 50(0) → 不足,跳过
  • 200(100) → 120 ≤ 200,分配。剩余:200-120 = 80 KB,起始地址 100+120 = 220
  • 新空闲列表:[50(0), 80(220), 80(500), 150(800), 24(1000)]

② 请求 B:50 KB

  • 50(0) → 50 ≤ 50,正好分配!移除该分区
  • 新空闲列表:[80(220), 80(500), 150(800), 24(1000)]

③ 请求 C:90 KB

  • 80(220) → 不足,跳过
  • 80(500) → 不足,跳过
  • 150(800) → 90 ≤ 150,分配。剩余:150-90 = 60 KB,起始地址 800+90 = 890
  • 新空闲列表:[80(220), 80(500), 60(890), 24(1000)]

④ 请求 D:30 KB

  • 80(220) → 30 ≤ 80,分配。剩余:80-30 = 50 KB,起始地址 220+30 = 250
  • 新空闲列表:[50(250), 80(500), 60(890), 24(1000)]

First-Fit 结果:4 个请求全部成功分配。

(2) 最佳适应算法(Best-Fit)

查找大小最接近请求的空闲分区(即能满足要求的最小空闲分区)。

初始空闲列表:[50(0), 200(100), 80(500), 150(800), 24(1000)]

① 请求 A:120 KB

  • 查找 ≥ 120 的最小分区:150(800)(差值30)或 200(100)(差值80)
  • 选 150(800)。剩余:150-120 = 30 KB,起始地址 800+120 = 920
  • 新空闲列表:[24(1000), 30(920), 50(0), 80(500), 200(100)](按大小排序后)
  • 实际上按地址排序:[50(0), 200(100), 80(500), 30(920), 24(1000)]

② 请求 B:50 KB

  • 查找 ≥ 50 的最小分区:50(0) 正好!
  • 移除 50(0)
  • 新空闲列表:[200(100), 80(500), 30(920), 24(1000)]

③ 请求 C:90 KB

  • 查找 ≥ 90 的最小分区:200(100)(差值110)或 80(500)(不足),
  • 选 200(100)。剩余:200-90 = 110 KB,起始地址 100+90 = 190
  • 新空闲列表:[80(500), 110(190), 30(920), 24(1000)]

④ 请求 D:30 KB

  • 查找 ≥ 30 的最小分区:30(920) 正好!
  • 移除 30(920)
  • 新空闲列表:[80(500), 110(190), 24(1000)]

Best-Fit 结果:4 个请求全部成功分配。

(3) 最差适应算法(Worst-Fit)

查找最大的空闲分区进行分配。

初始空闲列表:[50(0), 200(100), 80(500), 150(800), 24(1000)]

① 请求 A:120 KB

  • 最大空闲分区:200(100),分配 120 KB
  • 剩余:200-120 = 80 KB,起始地址 100+120 = 220
  • 新空闲列表:[150(800), 80(500), 80(220), 50(0), 24(1000)](按大小排序)
  • 按地址:[50(0), 80(220), 80(500), 150(800), 24(1000)]

② 请求 B:50 KB

  • 最大空闲分区:150(800),分配 50 KB
  • 剩余:150-50 = 100 KB,起始地址 800+50 = 850
  • 新空闲列表:[100(850), 80(500), 80(220), 50(0), 24(1000)]

③ 请求 C:90 KB

  • 最大空闲分区:100(850),分配 90 KB
  • 剩余:100-90 = 10 KB,起始地址 850+90 = 940
  • 新空闲列表:[80(500), 80(220), 50(0), 24(1000), 10(940)]

④ 请求 D:30 KB

  • 最大空闲分区:80(500),分配 30 KB
  • 剩余:80-30 = 50 KB,起始地址 500+30 = 530
  • 新空闲列表:[80(220), 50(530), 50(0), 24(1000), 10(940)]

Worst-Fit 结果:4 个请求全部成功分配。

算法对比总结

算法 分配结果 特点
First-Fit 成功分配,产生较多小碎片 地址导向,速度较快
Best-Fit 成功分配,产生极小碎片 容易产生很多无法利用的小碎片
Worst-Fit 成功分配,剩余分区较均衡 减少小碎片,但大分区被快速消耗

7. 页面置换算法

题目内容
某进程的页面访问序列(引用串)为:7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1

系统为该进程分配 3 个物理帧(初始为空)。请分别使用以下算法计算缺页次数和缺页率。

  1. FIFO(先进先出页面置换)
  2. LRU(最近最久未使用页面置换)
  3. OPT(最优页面置换)

考点:页面置换算法的缺页率分析

来源章节:第 5 章 — 内存管理之虚拟内存(页面置换)

完整解答过程

(1) FIFO 算法

缺页率 = 缺页次数 / 总访问次数。

序号 访问页面 帧1 帧2 帧3 是否缺页 说明
1 7 7 缺页✓ 装入 7
2 0 7 0 缺页✓ 装入 0
3 1 7 0 1 缺页✓ 装入 1
4 2 2 0 1 缺页✓ 替换 7(最先进)
5 0 2 0 1 命中 0 已在
6 3 2 3 1 缺页✓ 替换 0(先进)
7 0 2 3 0 缺页✓ 替换 1(先进)
8 4 4 3 0 缺页✓ 替换 2(先进)
9 2 4 2 0 缺页✓ 替换 3(先进)
10 3 4 2 3 缺页✓ 替换 0(先进)
11 0 4 2 0 缺页✓ 替换 3(先进?实际上是替换了3,但需仔细看)

等一下,让我更仔细地追踪 FIFO 的队列顺序。FIFO 需要维护一个页面进入帧的顺序队列。

FIFO 详细追踪(队列:左为最老,右为最新):

步骤 页面 帧内容(按加载时间) 队列(老→新) 缺页
1 7 [7, -, -] [7]
2 0 [7, 0, -] [7, 0]
3 1 [7, 0, 1] [7, 0, 1]
4 2 [2, 0, 1] [0, 1, 2] ✓ 替换7
5 0 [2, 0, 1] [0, 1, 2]
6 3 [2, 3, 1] [1, 2, 3] ✓ 替换0
7 0 [2, 3, 0] [2, 3, 0] ✓ 替换1
8 4 [4, 3, 0] [3, 0, 4] ✓ 替换2
9 2 [4, 2, 0] [0, 4, 2] ✓ 替换3
10 3 [4, 2, 3] [4, 2, 3] ✓ 替换0
11 0 [0, 2, 3] [2, 3, 0] ✓ 替换4
12 3 [0, 2, 3] [2, 3, 0]
13 2 [0, 2, 3] [2, 3, 0]
14 1 [0, 1, 3] [3, 0, 1] ✓ 替换2
15 2 [0, 1, 2] [0, 1, 2] ✓ 替换3
16 0 [0, 1, 2] [0, 1, 2]
17 1 [0, 1, 2] [0, 1, 2]
18 7 [7, 1, 2] [1, 2, 7] ✓ 替换0
19 0 [7, 0, 2] [2, 7, 0] ✓ 替换1
20 1 [7, 0, 1] [7, 0, 1] ✓ 替换2

FIFO 缺页次数 = 15 次
缺页率 = 15/20 = 75%

(2) LRU 算法

LRU 替换最长时间未被使用的页面。

LRU 详细追踪(帧内容按 LRU 顺序,最左为最近最久未使用):

步骤 页面 帧内容(最近使用→最久未使用) 缺页
1 7 [7]
2 0 [0, 7]
3 1 [1, 0, 7]
4 2 [2, 1, 0] ✓ 替换7
5 0 [0, 2, 1] ✗ 0命中,移至最近
6 3 [3, 0, 2] ✓ 替换1
7 0 [0, 3, 2] ✗ 0命中,移至最近
8 4 [4, 0, 3] ✓ 替换2
9 2 [2, 4, 0] ✓ 替换3
10 3 [3, 2, 4] ✓ 替换0
11 0 [0, 3, 2] ✓ 替换4
12 3 [3, 0, 2] ✗ 3命中,移至最近
13 2 [2, 3, 0] ✗ 2命中,移至最近
14 1 [1, 2, 3] ✓ 替换0
15 2 [2, 1, 3] ✗ 2命中,移至最近
16 0 [0, 2, 1] ✓ 替换3
17 1 [1, 0, 2] ✗ 1命中,移至最近
18 7 [7, 1, 0] ✓ 替换2
19 0 [0, 7, 1] ✗ 0命中,移至最近
20 1 [1, 0, 7] ✗ 1命中,移至最近

LRU 缺页次数 = 12 次
缺页率 = 12/20 = 60%

(3) OPT 算法(Optimal,最优置换)

OPT 替换未来最长时间不会被使用的页面。

OPT 详细追踪(需要预知未来的访问序列以决定替换哪个页面):

步骤 页面 帧内容 缺页 替换决策(未来最远使用的页面)
1 7 [7]
2 0 [7, 0]
3 1 [7, 0, 1]
4 2 [2, 0, 1] 7在未来步18才用,最远 → 替换7
5 0 [2, 0, 1]
6 3 [2, 0, 3] 替换1,因为1未来在步14,而2在步9,0在步11,所以1最远
7 0 [2, 0, 3]
8 4 [2, 0, 4] 替换3,因为3未来在步10(较近),而2在步9,0在步11;故4在步8后不再使用 → 替换3
9 2 [2, 0, 4]
10 3 [2, 0, 3] 替换4(4不再出现)
11 0 [2, 0, 3]
12 3 [2, 0, 3]
13 2 [2, 0, 3]
14 1 [1, 0, 3] 2未来在步15较近,0在步16,3在步…其实3不再出现(步12后3不再使用)。所以替换3或2?步13后2在步15用,3不用了。替换2或3。3不用了 → 替换3或2,选不用的那个。替换3较好
15 2 [1, 0, 2] 替换…实际上在第14步我替换了3,所以帧是[1,0,3],步15访问2,2不在,缺页。帧中1在步17,0在步16,3不再用 → 替换3
16 0 [1, 0, 2]
17 1 [1, 0, 2]
18 7 [7, 0, 2] 1在步17后用完了,替换1
19 0 [7, 0, 2]
20 1 [7, 0, 1] 替换2(2不再出现)

让我们重新仔细做 OPT:

初始帧:空

  1. 7 → 缺页,帧:[7]
  2. 0 → 缺页,帧:[7, 0]
  3. 1 → 缺页,帧:[7, 0, 1]
  4. 2 → 缺页,帧:[2, 0, 1] — 替换7(7在步18才出现,最远)
  5. 0 → 命中,帧:[2, 0, 1]
  6. 3 → 缺页,帧:[2, 0, 3] — 替换1(1在步14出现,2在步9,0在步11,1最远)
  7. 0 → 命中,帧:[2, 0, 3]
  8. 4 → 缺页,帧:[2, 0, 4] — 替换3(3在步10出现,2在步9,0在步11,但步10较近…等等,需要比较3个页面下一次出现的位置:
    • 2 → 步9
    • 0 → 步11
    • 3 → 步10
    • 4 → 以后不再出现
      所以应替换4的页面不对!4是新页面,帧中的旧页面2、0、3中,以后出现最远的是3(步10)还是0(步11)?最远的是0(步11)?不对,步6到步8的决策:
      帧中:[2, 0, 3],访问4,缺页。检查帧中三个页面未来出现位置:
    • 2 → 步9
    • 0 → 步11
    • 3 → 步10
      最远的是0(步11),所以应替换0?不对,“最远"是指"最晚被使用”,即出现位置最大的那个。步11 > 步10 > 步9,所以0最远 → 替换0?但0马上在步11就被访问了…

等等,让我重新理解OPT算法。OPT是替换"未来最长时间不会被使用"的页面,即未来第一次出现最晚的那个。

在步8,访问4,帧为[2,0,3]。各页面未来第一次出现位置:

  • 2: 步9
  • 0: 步11
  • 3: 步10

最晚出现的是0(步11),所以应替换0。

继续:

6(重做). 3 → 缺页,帧:[2, 3, 1] — 替换0?不对,步6时的帧为[2,0,1],访问3。检查:

  • 2 → 步9
  • 0 → 步11(等等,步5已经用了0,后面的0在步7和步11)
  • 1 → 步14
    步14 > 步11 > 步9,所以1最远 → 替换1,帧:[2, 0, 3]

好吧,步6我做的对了。

步8:访问4,帧:[2,0,3]:

  • 2 → 步9
  • 0 → 步11
  • 3 → 步10
    最远是0(步11),替换0,帧:[2, 4, 3]

步9:访问2 → 命中,帧:[2, 4, 3]

步10:访问3 → 命中,帧:[2, 4, 3]

步11:访问0 → 缺页,帧:[2, 0, 3] — 帧中:[2,4,3]。检查:

  • 2 → 步13(步9之后的2在步13和步15)
  • 4 → 此后不再使用
  • 3 → 步12
    4不再使用 → 替换4,帧:[2, 0, 3]

步12:访问3 → 命中,帧:[2, 0, 3]

步13:访问2 → 命中,帧:[2, 0, 3]

步14:访问1 → 缺页,帧:[1, 0, 3] — 帧中:[2,0,3],检查:

  • 2 → 步15
  • 0 → 步16
  • 3 → 此后不再使用
    3不再使用 → 替换3,帧:[2, 0, 1]

步15:访问2 → 命中,帧:[2, 0, 1]

步16:访问0 → 命中,帧:[2, 0, 1]

步17:访问1 → 命中,帧:[2, 0, 1]

步18:访问7 → 缺页,帧:[7, 0, 1] — 帧中[2,0,1],检查:

  • 2 → 此后不再使用
  • 0 → 步19
  • 1 → 步20
    2不再使用 → 替换2,帧:[7, 0, 1]

步19:访问0 → 命中,帧:[7, 0, 1]

步20:访问1 → 命中,帧:[7, 0, 1]

汇总OPT:
缺页发生在步:1, 2, 3, 4, 6, 8(替换0), 11(替换4), 14(替换3), 18(替换2)
缺页次数 = 9次

不对,步8替换0,但步11重新访问0又缺页…这是因为步8我把0替换出去了。让我再仔细跟踪一下。

重新做OPT,这次更仔细:

帧: 最多3个页面。初始空。

步1: 访问7 → 缺页。帧: [7, -, -]
步2: 访问0 → 缺页。帧: [7, 0, -]
步3: 访问1 → 缺页。帧: [7, 0, 1]
步4: 访问2 → 缺页。帧中[7,0,1]已满,需替换。

  • 7未来出现: 步18
  • 0未来出现: 步5, 7, 11 → 首次步5
  • 1未来出现: 步14
    最远: 7(步18) → 替换7。帧: [2, 0, 1]
    步5: 访问0 → 命中。帧: [2, 0, 1]
    步6: 访问3 → 缺页。帧[2,0,1]已满。
  • 2未来出现: 步9
  • 0未来出现: 步7
  • 1未来出现: 步14
    最远: 1(步14) → 替换1。帧: [2, 0, 3]
    步7: 访问0 → 命中。帧: [2, 0, 3]
    步8: 访问4 → 缺页。帧[2,0,3]已满。
  • 2未来出现: 步9
  • 0未来出现: 步11
  • 3未来出现: 步10
    最远: 0(步11) → 替换0。帧: [2, 4, 3]
    步9: 访问2 → 命中。帧: [2, 4, 3]
    步10: 访问3 → 命中。帧: [2, 4, 3]
    步11: 访问0 → 缺页。帧[2,4,3]已满。
  • 2未来出现: 步13
  • 4未来出现: 不再出现
  • 3未来出现: 步12
    不再出现优先 → 替换4。帧: [2, 0, 3]
    步12: 访问3 → 命中。帧: [2, 0, 3]
    步13: 访问2 → 命中。帧: [2, 0, 3]
    步14: 访问1 → 缺页。帧[2,0,3]已满。
  • 2未来出现: 步15
  • 0未来出现: 步16
  • 3未来出现: 不再出现
    不再出现优先 → 替换3。帧: [2, 0, 1]
    步15: 访问2 → 命中。帧: [2, 0, 1]
    步16: 访问0 → 命中。帧: [2, 0, 1]
    步17: 访问1 → 命中。帧: [2, 0, 1]
    步18: 访问7 → 缺页。帧[2,0,1]已满。
  • 2未来出现: 不再出现
  • 0未来出现: 步19
  • 1未来出现: 步20
    不再出现优先 → 替换2。帧: [7, 0, 1]
    步19: 访问0 → 命中。帧: [7, 0, 1]
    步20: 访问1 → 命中。帧: [7, 0, 1]

OPT 缺页步: 1, 2, 3, 4, 6, 8, 11, 14, 18 = 9 次
缺页率 = 9/20 = 45%

(4) LFU 算法(最不频繁使用)

LFU(Least Frequently Used)替换访问频率最低的页面。若多个页面频率相同,采用 FIFO 策略(先进入者先出)打破平局。

需要维护每个页面的访问计数装入时间(用于 FIFO 打破平局)。

LFU 详细追踪(帧内容 + 访问频率表):

步骤 页面 帧内容 缺页 访问频率(帧内页面) 说明
1 7 [7, -, -] 7:1 装入 7
2 0 [7, 0, -] 7:1, 0:1 装入 0
3 1 [7, 0, 1] 7:1, 0:1, 1:1 装入 1
4 2 [2, 0, 1] 2:1, 0:1, 1:1 频率全为1,FIFO替换最老的7(步1装入),帧:[2,0,1]
5 0 [2, 0, 1] 0:2, 1:1, 2:1 0命中,频率+1
6 3 [2, 0, 3] 2:1, 0:2, 3:1 最低频率:2(1)和1(1),FIFO:1(步3)老于2(步4)→替换1,帧:[2,0,3]
7 0 [2, 0, 3] 0:3, 2:1, 3:1 0命中,频率+1
8 4 [4, 0, 3] 4:1, 0:3, 3:1 最低频率:2(1)和3(1),FIFO:2(步4)老于3(步6)→替换2,帧:[4,0,3]
9 2 [4, 0, 2] 4:1, 0:3, 2:1 最低频率:4(1)和3(1),FIFO:3(步6)老于4(步8)→替换3,帧:[4,0,2]
10 3 [3, 0, 2] 3:1, 0:3, 2:1 最低频率:4(1)和2(1),FIFO:4(步8)老于2(步9)→替换4,帧:[3,0,2]
11 0 [3, 0, 2] 0:4, 3:1, 2:1 0命中,频率+1
12 3 [3, 0, 2] 3:2, 0:4, 2:1 3命中,频率+1
13 2 [3, 0, 2] 3:2, 0:4, 2:2 2命中,频率+1
14 1 [3, 0, 1] 3:2, 0:4, 1:1 最低频率:3(2)和2(2),FIFO:2(步9)老于3(步10)→替换2,帧:[3,0,1]
15 2 [3, 0, 2] 3:2, 0:4, 2:1 最低频率:3(2)和1(1),1频率更低→替换1,帧:[3,0,2]
16 0 [3, 0, 2] 0:5, 3:2, 2:1 0命中,频率+1
17 1 [3, 0, 1] 3:2, 0:5, 1:1 最低频率:3(2)和2(1),2频率更低→替换2,帧:[3,0,1]
18 7 [3, 0, 7] 3:2, 0:5, 7:1 最低频率:3(2)和1(1),1频率更低→替换1,帧:[3,0,7]
19 0 [3, 0, 7] 0:6, 3:2, 7:1 0命中,频率+1
20 1 [3, 0, 1] 3:2, 0:6, 1:1 最低频率:3(2)和7(1),7频率更低→替换7,帧:[3,0,1]

LFU 缺页步: 1, 2, 3, 4, 6, 8, 9, 10, 14, 15, 17, 18, 20 = 13 次
LFU 缺页率 = 13/20 = 65%

LFU 算法特点分析

  • LFU 的理论依据是:过去经常使用的页面将来也会经常使用
  • 优点:对"热点页面"(如循环中被频繁访问的代码页)非常友好,不易被替换
  • 缺点
    • 实现开销大(需维护每个页面的计数器)
    • 存在"历史惯性"问题——曾经很"热"但现在已经不用了的页面,因计数高而赖着不走(如步14-18中,3的频率为2但实际已很少使用,1频率为1却多次被替换)
    • 对新换入的页面不友好(新页面的初始计数为1,很容易被再次换出)

最终汇总

算法 缺页次数 缺页率
FIFO 15 75%
LFU 13 65%
LRU 12 60%
OPT 9 45%

综合结论:OPT 算法性能最佳(理论上,无法实现),LRU 最接近 OPT,LFU 介于 FIFO 和 LRU 之间,FIFO 最差。OPT 作为理想算法无法在实际系统中实现,但可作为衡量其他算法性能的上界参考。LRU 和 LFU 各有适用场景:LRU 对顺序访问友好,LFU 对热点页面友好。


8. 磁盘调度算法

题目内容
某磁盘有 200 个柱面,编号从 0~199。磁盘请求队列中包含以下柱面号(按到达顺序):

请求队列:98, 183, 37, 122, 14, 124, 65, 67

当前磁头位于 53 号柱面,正在向柱面号增大的方向(即向外)移动。

请分别计算以下磁盘调度算法的磁头移动总距离(总寻道长度,以柱面数为单位),并给出磁头移动的顺序。

  1. FCFS(先来先服务)
  2. SSTF(最短寻道时间优先)
  3. SCAN(电梯算法,向增大方向移动,直到最末端再折返)
  4. C-SCAN(循环扫描,向增大方向移动,到最末端后直接回到最前端)

考点:磁盘调度算法的寻道时间计算

来源章节:第 7 章 — 设备管理之磁盘调度

完整解答过程

(1) FCFS(先来先服务)

按请求到达顺序依次服务。

移动顺序:53 → 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67

寻道距离计算

移动 距离
53→98 增大 45
98→183 增大 85
183→37 减小 146
37→122 增大 85
122→14 减小 108
14→124 增大 110
124→65 减小 59
65→67 增大 2

总寻道长度 = 45 + 85 + 146 + 85 + 108 + 110 + 59 + 2 = 640 个柱面

(2) SSTF(最短寻道时间优先)

每次选择距离当前磁头位置最近的请求。

逐步分析

初始位置:53

步骤 当前位置 候选请求 最短距离 选中 移动距离
1 53 98(45), 183(130), 37(16), 122(69), 14(39), 124(71), 65(12), 67(14) 12(65) 65 12
2 65 98(33), 183(118), 37(28), 122(57), 14(51), 124(59), 67(2) 2(67) 67 2
3 67 98(31), 183(116), 37(30), 122(55), 14(53), 124(57) 30(37) 37 30
4 37 98(61), 183(146), 14(23), 122(85), 124(87) 23(14) 14 23
5 14 98(84), 183(169), 122(108), 124(110) 84(98) 98 84
6 98 183(85), 122(24), 124(26) 24(122) 122 24
7 122 183(61), 124(2) 2(124) 124 2
8 124 183(59) 59(183) 183 59

移动顺序:53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183

总寻道长度 = 12 + 2 + 30 + 23 + 84 + 24 + 2 + 59 = 236 个柱面

(3) SCAN(电梯算法)

磁头当前在 53,向增大方向移动。服务沿途所有请求,到达 199 后折返向减小方向继续服务剩余请求。

排序请求:14, 37, 65, 67, 98, 122, 124, 183

移动路径:53 → 65 → 67 → 98 → 122 → 124 → 183 → 199(末端) → 37 → 14

移动 距离
53→65 增大 12
65→67 增大 2
67→98 增大 31
98→122 增大 24
122→124 增大 2
124→183 增大 59
183→199 增大(到末端) 16
199→37 减小 162
37→14 减小 23

总寻道长度 = 12 + 2 + 31 + 24 + 2 + 59 + 16 + 162 + 23 = 331 个柱面

注意:SCAN 可以从当前方向服务完即止(如果题目说不需到末端)。从题意看通常到最末端再折返(“向增大方向移动,直到最末端再折返”)。

(4) C-SCAN(循环扫描)

磁头向增大方向移动,服务沿途所有请求,到达 199 后直接返回 0,再从 0 向增大方向移动。

排序请求:14, 37, 65, 67, 98, 122, 124, 183

移动路径:53 → 65 → 67 → 98 → 122 → 124 → 183 → 199(末端)0(回到起点) → 14 → 37

移动 距离
53→65 增大 12
65→67 增大 2
67→98 增大 31
98→122 增大 24
122→124 增大 2
124→183 增大 59
183→199 增大(到末端) 16
199→0 直接回起点 199
0→14 增大 14
14→37 增大 23

总寻道长度 = 12 + 2 + 31 + 24 + 2 + 59 + 16 + 199 + 14 + 23 = 382 个柱面

结果汇总

算法 总寻道长度(柱面数) 移动顺序
FCFS 640 53→98→183→37→122→14→124→65→67
SSTF 236 53→65→67→37→14→98→122→124→183
SCAN 331 53→65→67→98→122→124→183→199→37→14
C-SCAN 382 53→65→67→98→122→124→183→199→0→14→37

结论:SSTF 在本例中总寻道长度最小,但 SSTF 可能导致"饥饿"问题。SCAN 和 C-SCAN 虽然寻道距离稍大,但提供了更公平的服务,C-SCAN 比 SCAN 的等待时间方差更小。


9. 死锁检测

题目内容
某系统有 4 个进程 P1~P4 和 4 种资源 R1~R4。当前资源分配情况如下:

已分配矩阵 Allocation

进程 R1 R2 R3 R4
P1 0 1 1 0
P2 1 0 0 1
P3 0 1 0 0
P4 1 0 1 0

请求矩阵 Request(表示每个进程当前还需要的资源数):

进程 R1 R2 R3 R4
P1 0 0 0 1
P2 1 1 0 0
P3 1 0 0 1
P4 1 0 0 0

可用资源 Available = (0, 0, 1, 0)

请分析:

  1. 当前系统是否存在死锁?使用死锁检测算法逐步分析。
  2. 如果存在死锁,哪些进程处于死锁状态?

考点:死锁检测算法(资源分配图化简法 / 矩阵分析法)

来源章节:第 8 章 — 死锁检测

完整解答过程

方法:使用死锁检测算法(类似于银行家算法但不要求 Max):

步骤1:初始化

  • Work = Available = (0, 0, 1, 0)
  • Finish[i] = False(对所有 i,表示进程未完成)

步骤2:标记 Allocation 全为 0 的进程为 Finish=True
P1: Allocation = (0,1,1,0) ≠ 0 → Finish[1]=False
P2: Allocation = (1,0,0,1) ≠ 0 → Finish[2]=False
P3: Allocation = (0,1,0,0) ≠ 0 → Finish[3]=False
P4: Allocation = (1,0,1,0) ≠ 0 → Finish[4]=False
所有进程均已获得资源。

步骤3:查找满足条件的进程(Request[i] ≤ Work 且 Finish[i]=False)

轮次 Work 可满足的进程 说明
第1轮 (0,0,1,0) P4: Request=(1,0,0,0) → 1 > 0,不满足
P1: Request=(0,0,0,1) → 1 > 0,不满足
P2: Request=(1,1,0,0) → 均不满足
P3: Request=(1,0,0,1) → 均不满足
无进程可满足

步骤4:结果分析

无进程可以被满足,因此所有进程的 Finish 均为 False,系统处于死锁状态。

答(第1问):当前系统存在死锁。

答(第2问):所有 4 个进程 P1、P2、P3、P4 均处于死锁状态。

验证:让我们用资源分配图来验证。

每个进程已分配资源和请求资源:

  • P1: 已分配 R2×1, R3×1;请求 R4×1
  • P2: 已分配 R1×1, R4×1;请求 R1×1, R2×1
  • P3: 已分配 R2×1;请求 R1×1, R4×1
  • P4: 已分配 R1×1, R3×1;请求 R1×1

可用资源:R3×1

分析资源分配图环路:

  • Available 有 R3×1,但 R3 分配给 P1×1、P4×1,可使用 R3 的进程…
  • P1 需要 R4,R4 分配给 P2,P2 需要 R1 和 R2…
  • 存在环路:P1 → R4 → P2 → R1 → P4 → R3 → P1(或类似的环路)
  • 或者:P1 → R4 → P2 → R2 → P3 → R1 → P4 → R3 → P1

确认死锁:存在环路且每个资源在环路中只有单个实例。

所以结论正确:所有 4 个进程均处于死锁状态。


10. CHS / LBA 地址转换

题目内容
某硬盘的参数如下:

  • 磁头数(Heads):8
  • 每磁道扇区数(Sectors per track):63
  • 柱面数(Cylinders):2048

请回答以下问题:

  1. 该硬盘的总容量是多少扇区?如果每扇区 512 字节,总容量为多少?
  2. 将 CHS 地址 (C=100, H=3, S=20) 转换为 LBA(逻辑块地址)。
  3. 将 LBA 地址 500000 转换为 CHS 地址。
  4. 如果将 LBA 视为一维连续编址,从 LBA=0 开始,请问 LBA=0 对应的 CHS 地址是什么?

考点:CHS 与 LBA 地址转换原理

来源章节:第 6 章 — 文件管理与磁盘结构

完整解答过程

基本公式

CHS → LBA

LBA = (C × Heads + H) × SectorsPerTrack + (S - 1)

LBA → CHS

C = LBA / (Heads × SectorsPerTrack)
H = (LBA / SectorsPerTrack) % Heads
S = (LBA % SectorsPerTrack) + 1

其中 C(柱面号),H(磁头号),S(扇区号,从 1 开始)。
LBA 从 0 开始编号。

第1问:总容量

总扇区数 = 柱面数 × 磁头数 × 每磁道扇区数
= 2048 × 8 × 63 = 2048 × 504 = 1,032,192 扇区

总字节数 = 1,032,192 × 512 = 528,482,304 字节 ≈ 504 MB

第2问:CHS → LBA

已知 C=100, H=3, S=20

LBA = (C × Heads + H) × SectorsPerTrack + (S - 1)
= (100 × 8 + 3) × 63 + (20 - 1)
= (800 + 3) × 63 + 19
= 803 × 63 + 19
= 50,589 + 19
= 50,608

:CHS(100, 3, 20) → LBA = 50,608

第3问:LBA → CHS

已知 LBA = 500,000

计算柱面号 C
C = LBA / (Heads × SectorsPerTrack)
= 500,000 / (8 × 63)
= 500,000 / 504
= 992(取整)… 让我们详细算:
504 × 992 = 504 × 1000 - 504 × 8 = 504,000 - 4,032 = 499,968
余数 = 500,000 - 499,968 = 32

所以 C = 992

计算磁头号 H
H = (LBA / SectorsPerTrack) % Heads
先算 temp = LBA / SectorsPerTrack = 500,000 / 63
63 × 7936 = 63 × 8000 - 63 × 64 = 504,000 - 4,032 = 499,968
余数 = 500,000 - 499,968 = 32
所以 temp = 7,936 余 32

H = 7,936 % 8
7,936 ÷ 8 = 992 余 0
所以 H = 0

计算扇区号 S
S = (LBA % SectorsPerTrack) + 1
LBA % 63 = 500,000 % 63
63 × 7,936 = 499,968
500,000 - 499,968 = 32
所以 S = 32 + 1 = 33

或用余数验证:余数 = 500,000 - 504 × 992 = 500,000 - 499,968 = 32
S = 32 + 1 = 33

验证:S = (32) + 1 = 33?

等等,让我重新检查。从 C=992 的余数 32 应该就是 S-1…不对。

让我一步步重新算:
LBA = 500,000

先用总公式检查
C = LBA / (H × SPT) = 500,000 / (8 × 63) = 500,000 / 504

504 × 992 = 499,968,余 32

所以 LBA 位于柱面 992。

然后在这个柱面内
柱面内的偏移 = LBA - C × (H × SPT) = 500,000 - 992 × 504 = 500,000 - 499,968 = 32

H = 柱面内偏移 / SPT = 32 / 63 = 0(取整)
S = (柱面内偏移 % SPT) + 1 = (32 % 63) + 1 = 32 + 1 = 33

所以 C = 992, H = 0, S = 33

验证:LBA = (992 × 8 + 0) × 63 + (33 - 1) = 7,936 × 63 + 32 = 499,968 + 32 = 500,000 ✓

:LBA 500,000 → CHS(992, 0, 33)

第4问:LBA=0 对应的 CHS

LBA = 0
C = 0 / (8 × 63) = 0
H = (0 / 63) % 8 = 0 % 8 = 0
S = (0 % 63) + 1 = 0 + 1 = 1

:LBA=0 → CHS(0, 0, 1)

最终答案汇总

问题 结果
1. 总容量 1,032,192 扇区 ≈ 504 MB
2. CHS(100,3,20) → LBA LBA = 50,608
3. LBA 500,000 → CHS CHS(992, 0, 33)
4. LBA=0 → CHS CHS(0, 0, 1)

11. 多级页表地址翻译

题目内容
考虑一个具备页式 MMU 的 x86-64 处理器,采用 4 级页表:

(1)假设处理器是 48 位虚拟地址,每级页表大小为 4KB,页大小为 4KB。请说明地址翻译的具体过程(1 分),以及每一级页表分别翻译多少位地址(1 分)。

(2)接(1),问此处理器的一次应用程序访存最多可能导致硬件实际进行多少次内存访问?请说明计算过程(2 分)。

(3)接(2),假设该处理器具备一个 TLB 和一个 L1 数据缓存,且所有页表查询被看作数据访问。假设 TLB 命中时,若 L1 缓存命中则需 1 个时钟周期,若 L1 缓存不命中则需 10 个时钟周期。问一次应用程序访存最长需要多少周期(1 分),最短需要多少周期(1 分),无须给出计算过程。

(4)接(1),假设操作系统采用写时复制(Copy-on-Write, COW)技术来优化 fork() 系统调用。请解释 COW 技术如何减少内存开销(1 分),并说明在什么情况下 COW 必须真正复制物理页面(1 分)。

(5)接(1),请说明多级页表相对于单级页表的两个主要优点(1 分)和一个主要缺点(1 分)。

考点:多级页表地址翻译过程、TLB 与 Cache 交互延迟分析、COW 机制、多级页表优缺点

来源章节:第 5 章 — 内存管理之分页存储

完整解答过程

(1)地址翻译过程与各级翻译位数

地址翻译过程

48 位虚拟地址在 4 级页表下的结构为:

| PML4(9位) | PDPT(9位) | PD(9位) | PT(9位) | 页内偏移(12位) |

因为页大小为 4KB = 2¹²,所以页内偏移占 12 位。剩余 48 - 12 = 36 位用于页号,分为 4 级,每级 36 ÷ 4 = 9 位。

每级页表大小 4KB,每项 8 字节(64 位系统),故每级页表包含 4KB ÷ 8B = 512 = 2⁹ 项,恰好对应 9 位索引。

地址翻译具体过程

  1. 第1级:从 CR3 寄存器获取 PML4(Page Map Level 4)基址,用虚拟地址的 PML4 字段(第 47~39 位)作为索引,找到 PDPT 页表的物理基址
  2. 第2级:用 PDPT 字段(第 38~30 位)在 PDPT 页表中索引,找到 PD(Page Directory)页表的物理基址
  3. 第3级:用 PD 字段(第 29~21 位)在 PD 页表中索引,找到 PT(Page Table)页表的物理基址
  4. 第4级:用 PT 字段(第 20~12 位)在 PT 页表中索引,得到最终的物理帧号
  5. 拼接:物理帧号 × 4KB + 页内偏移(第 11~0 位)= 物理地址

各级翻译位数:每级翻译 9 位,共 4 × 9 = 36 位页号,加上 12 位页内偏移 = 48 位。

(2)最坏情况内存访问次数

最坏情况:TLB 全部不命中,每次都要遍历全部 4 级页表。

一次完整地址翻译需要:

  • 第1级:访问 PML4(1次内存访问)
  • 第2级:访问 PDPT(1次内存访问)
  • 第3级:访问 PD(1次内存访问)
  • 第4级:访问 PT(1次内存访问)
  • 最后:访问实际数据(1次内存访问)

最坏情况总计:4(查页表)+ 1(取数据)= 5 次内存访问

:最多 5 次内存访问。

(3)最长与最短时钟周期

  • 最短(TLB 命中 + L1 缓存命中):只需 1 次取数据,TLB 命中意味着无需查页表,L1 命中意味着数据已经在缓存中。只需 1 个周期。最短 = 1 个周期

  • 最长(TLB 不命中 + 每次页表查询 L1 也不命中 + 最终数据也不命中):

    • 4 次查页表(TLB miss),每次查页表访问内存,若 L1 也 miss = 4 × 10 = 40 周期
    • 1 次取数据,L1 miss = 10 周期
    • 合计 = 50 周期

    最长 = 50 个周期

(4)Copy-on-Write(COW)技术

COW 如何减少内存开销

当父进程调用 fork() 创建子进程时,操作系统不立即复制父进程的所有物理页面,而是让父子进程共享同一组物理页面,并将这些页面标记为只读。只有当父进程或子进程尝试写入某个共享页面时,硬件触发缺页异常,操作系统才真正为该页面创建副本(复制物理页面),并更新两个进程的页表使其分别指向各自的私有副本。

这避免了 fork() 时一次性复制全部地址空间的开销(大量"复制了但从未被修改"的页面不产生实际副本)。

COW 必须真正复制物理页面的情况

当父进程或子进程尝试写入一个标记为 COW 的共享只读页面时:

  1. CPU 触发写保护缺页异常
  2. 操作系统识别为 COW 页面
  3. 分配一个新的物理帧
  4. 将原帧内容复制到新帧
  5. 更新写入进程的页表项指向新帧,并标记为可读写
  6. 将两个进程的原帧都标记为可读写(若另一个进程仍共享)

:当任一进程尝试写入共享的 COW 页面时,必须真正复制。

(5)多级页表 vs 单级页表

两个主要优点

  1. 节省内存空间:单级页表需要为整个虚拟地址空间连续分配页表(如 48 位 VA 需 2³⁶ 个页表项,即使只用了一小部分),而多级页表可以只为实际使用的地址范围分配页表(未使用的中间级页表项标记为"不存在",不分配下级页表)
  2. 无需连续物理内存:单级页表(如 36 位页号 → 2³⁶ × 8B = 512GB 的页表)需要巨大的连续物理内存存放,几乎不可能;多级页表将大页表拆成小块(每级 4KB),很容易分配

一个主要缺点

  • 增加访存次数:单级页表只需 1 次页表查询 + 1 次数据访问 = 2 次内存访问;4 级页表需要 4 次页表查询 + 1 次数据访问 = 5 次内存访问,增加了地址翻译的时间开销(TLB 命中时可以缓解)

12. TLB 与页表遍历的延迟分析

题目内容
某系统采用 4 级页表,页面大小 4KB。处理器具有 64 项的 TLB(全相联)。

(1)若进程的工作集(Working Set)大小为 256KB,请问 TLB 能否覆盖整个工作集(1 分)?若不能,工作集若多大才能被完全覆盖(1 分)?

(2)假设 TLB 命中率为 95%,L1 数据缓存命中率为 90%,L2 缓存命中率为 80%。TLB 命中时若数据在 L1 则需 1 周期,在 L2 则需 10 周期,在内存则需 100 周期。TLB 不命中时需额外遍历 4 级页表(每次页表查询均在 L1 中命中,各需 1 周期),然后按以上规则访问数据。求一次应用程序访存的平均延迟周期数(2 分)。

(3)在上述系统中,TLB 刷新(TLB flush)是一个开销较大的操作。请解释为什么在频繁的进程上下文切换中 TLB flush 会导致性能问题(1 分),并提出一种在不刷新全部 TLB 的前提下避免地址混淆的硬件机制(1 分)。

考点:TLB 覆盖范围计算、分级缓存下的平均访存延迟、TLB flush 与 ASID

来源章节:第 4 章(TLB)与第 5 章(内存管理)

完整解答过程

(1)TLB 覆盖范围

每个 TLB 项覆盖一个页面(4KB)。64 项 TLB 的覆盖范围 = 64 × 4KB = 256KB

:恰好可以覆盖 256KB 的工作集。若要完全覆盖,工作集最大为 256KB。

(2)平均访存延迟

分四种情况计算:

情况 A:TLB 命中 + L1 命中(数据)

  • 概率:0.95 × 0.90 = 0.855
  • 延迟:1 周期(无需查页表,数据在 L1)
  • 贡献:0.855 × 1 = 0.855

情况 B:TLB 命中 + L1 不命中 + L2 命中

  • 概率:0.95 × 0.10 × 0.80 = 0.076
  • 延迟:10 周期
  • 贡献:0.076 × 10 = 0.76

情况 C:TLB 命中 + L1 不命中 + L2 不命中

  • 概率:0.95 × 0.10 × 0.20 = 0.019
  • 延迟:100 周期
  • 贡献:0.019 × 100 = 1.9

情况 D:TLB 不命中(需遍历4级页表,每次都在L1命中)+ …

  • 概率:0.05
  • 页表遍历:4 次 L1 查询(每次 1 周期)= 4 周期
  • 然后数据访问:
    • L1 命中(0.90):+1 周期
    • L1 miss + L2 命中(0.10 × 0.80 = 0.08):+10 周期
    • L1 miss + L2 miss(0.10 × 0.20 = 0.02):+100 周期
  • 平均数据延迟 = 0.90 × 1 + 0.08 × 10 + 0.02 × 100 = 0.9 + 0.8 + 2.0 = 3.7 周期
  • 情况 D 总延迟 = 4 + 3.7 = 7.7 周期
  • 贡献:0.05 × 7.7 = 0.385

总平均延迟 = 0.855 + 0.76 + 1.9 + 0.385 = 3.9 周期

(3)TLB flush 的问题与解决方案

TLB flush 导致性能问题的原因

不同进程有不同的虚拟地址空间(各自独立的页表)。上下文切换时,若不刷新 TLB,新进程可能错误命中旧进程留在 TLB 中的页表项(虚拟地址相同但物理地址不同),导致访问到错误的物理内存。因此每次切换进程必须刷新 TLB。但 TLB flush 后,新进程的所有访存都从 TLB miss 开始(称为 “冷启动”),必须重新遍历页表,大幅增加初始访存延迟。频繁的进程切换会导致 TLB 持续处于"冷"状态,命中率急剧下降。

硬件机制——ASID(Address Space Identifier,地址空间标识符)

为每个进程分配一个唯一的ASID,TLB 项中增加 ASID 字段。TLB 查找时,同时匹配虚拟页号和 ASID。上下文切换时只需切换到新进程的 ASID(无需刷新 TLB),既避免了地址混淆,又保留了旧进程的热 TLB 项(当切换回该进程时仍可命中)。x86 的 PCID(Process-Context Identifier)和 ARM 的 ASID 均采用此机制。


13. 倒排页表与哈希页表

题目内容
某 64 位系统采用倒排页表(Inverted Page Table,IPT)管理内存,物理内存 4GB,页大小 4KB。

(1)传统页表的页表项数量由虚拟地址空间大小决定,倒排页表的页表项数量由什么决定(1 分)?请计算该系统中倒排页表的页表项数量(1 分)。

(2)请简要说明倒排页表的地址翻译过程(2 分)。为什么倒排页表通常需要结合哈希表来加速查找(1 分)?

(3)倒排页表在地址翻译过程中如何处理哈希冲突(1 分)?请说明链地址法的基本思路。

(4)倒排页表相对于传统多级页表的一个主要优点和一个主要缺点分别是什么(2 分)?

(5)PowerPC 和 IA-64 架构采用了倒排页表。若物理内存升至 64GB(页大小不变),倒排页表的大小会如何变化(1 分)?传统多级页表的大小会因此改变吗(1 分)?

考点:倒排页表的原理、与传统页表的对比、哈希加速查找与冲突处理

来源章节:第 5 章 — 内存管理之分页存储

完整解答过程

(1)倒排页表大小

倒排页表由物理内存大小决定(而非虚拟地址空间大小)。传统页表有多少虚拟页就多少项;倒排页表则是多少物理帧就多少项。

物理内存 4GB,页大小 4KB:
物理帧数 = 4GB ÷ 4KB = 2³² ÷ 2¹² = 2²⁰ = 1,048,576 帧

:倒排页表约有 100 万项(1M 项)。

(2)地址翻译过程与哈希加速

地址翻译过程

  1. 将虚拟地址分解为:页号(VPN,高位)+ 页内偏移(低 12 位)
  2. 以虚拟页号(VPN)为输入,通过哈希函数计算哈希值
  3. 用哈希值索引哈希表,定位倒排页表中的候选条目
  4. 遍历冲突链,逐项比对 VPN 是否匹配
  5. 匹配成功后,取该倒排页表项的物理帧号
  6. 物理地址 = 物理帧号 × 4KB + 页内偏移

为什么需要哈希表加速

倒排页表只有约 100 万项(物理帧数),而 64 位虚拟地址有 2⁵² 个虚拟页。若每次地址翻译都线性搜索整个倒排页表来匹配 VPN,性能不可接受。哈希表可以将 O(n) 降到平均 O(1),大幅加速查找。

(3)哈希冲突处理——链地址法

倒排页表按哈希值分组。哈希值相同的多个虚拟页通过链表连接。

翻译时:遍历哈希槽对应的冲突链,逐个比对每个倒排页表项中的 VPN 字段,直到找到匹配(或遍历结束 → 缺页)。

(4)主要优缺点

优点节省内存。传统页表大小 ∝ 虚拟地址空间(即便物理内存很小,页表也可能非常大);倒排页表大小 ∝ 物理内存(无论虚拟地址多到多少位,页表大小只取决于实际装了多大内存)。在 64 位系统中,物理内存通常远小于虚拟地址空间,倒排页表大幅节约页表内存。

缺点地址翻译更复杂、更慢。传统页表 O(1)(直接页号索引),倒排页表需要哈希计算 + 冲突链遍历,翻译延迟更高;而且共享内存实现困难(一个物理帧被多个进程共享时,倒排页表通常只记录一个反向映射,难以处理多对一关系)。

(5)内存升级的影响

倒排页表:物理内存升至 64GB,页大小不变 → 物理帧数 = 64GB ÷ 4KB = 16M = 1,677 万帧,倒排页表大小增大 16 倍(正比于物理内存大小)。

传统多级页表大小不变,因为传统页表大小由虚拟地址空间(虚拟页号位数)决定,与物理内存大小无关。


14. 大页与 TLB 覆盖

题目内容
某系统虚拟地址 48 位,TLB 有 64 项。分别考虑三种页面大小:4KB(标准页)、2MB(大页)、1GB(巨页)。

(1)请计算三种页面大小下 TLB 的最大覆盖范围(TLB Reach),并填写下表(3 分):

页面大小 TLB 项数 TLB 最大覆盖范围
4KB 64 ?
2MB 64 ?
1GB 64 ?

(2)某数据库进程的工作集约为 200MB,主流程集中在约 100MB 的连续数据区。请问分别使用 4KB 和 2MB 页面时,TLB 是否能覆盖其核心工作集(2 分)?

(3)使用大页可能带来哪些负面影响?列举两个(2 分)。

(4)在采用 2MB 大页的情况下,虚拟地址的页内偏移占多少位?虚拟页号占多少位(1 分)?若仍采用 4 级页表结构,每级页表翻译多少位(提示:页大小变化可能影响页表级数)(2 分)?

考点:TLB Reach 计算、大页优缺点、不同页面大小下的地址结构

来源章节:第 4 章(TLB)与第 5 章(内存管理)

完整解答过程

(1)TLB 覆盖范围

页面大小 TLB 项数 TLB 最大覆盖范围
4KB 64 64 × 4KB = 256KB
2MB 64 64 × 2MB = 128MB
1GB 64 64 × 1GB = 64GB

可以看到,大页使 TLB 覆盖范围数量级增大:从 256KB 到 128MB 到 64GB。

(2)工作集覆盖分析

4KB 页面:TLB 覆盖 = 256KB,远小于 100MB 核心工作集 → 无法覆盖,几乎所有访问都会触发 TLB miss,频繁遍历页表。

2MB 页面:TLB 覆盖 = 128MB,大于 100MB 核心工作集 → 可以完全覆盖,TLB 命中率高,性能显著提升。

(3)大页的负面影响

  1. 内部碎片严重:若进程只需 10KB 数据却分配了一个 2MB 大页,剩余约 1.99MB 空间被浪费(进程用不上,也不能给其他进程用)。

  2. 换页(swap)开销增大:页面置换时,换出/换入一个 2MB 或 1GB 页面的 I/O 时间远大于 4KB 页面,可能导致更明显的延迟抖动。

  3. 降低页面管理灵活性:操作系统无法在大页内部进行精细化的页面保护(如只保护其中几个字节)、COW 共享等操作的最小粒度变为大页。

(任写两个即可)

(4)2MB 大页下的地址结构

页内偏移:2MB = 2²¹ 字节 → 页内偏移占 21 位

虚拟页号:48 - 21 = 27 位

页表级数变化

每级页表 4KB,每项 8 字节 → 每级 512 项 → 9 位/级。

27 位页号 ÷ 9 位/级 = 3 级。

所以采用 2MB 页面时只需 3 级页表,每级各翻译 9 位。比 4KB 页面的 4 级少了一级,减少了一次内存访问。

:页内偏移 21 位,页号 27 位,需 3 级页表,每级 9 位。


15. 综合:fork() 与页表复制

题目内容
Linux 系统中,fork() 系统调用创建一个与父进程几乎完全相同的子进程。

(1)fork() 创建子进程时,在内存管理方面需要做哪些工作?请至少列出三项(3 分)。

(2)fork() 利用 COW(写时复制)避免立即复制父进程的全部物理页面。请解释:在 fork() 刚返回后,父子进程的页表分别指向什么物理页面(1 分)?这些物理页面的页表项中的权限位有何特殊之处(1 分)?

(3)假设子进程在 fork() 后立即调用 execve() 加载一个新程序。如果 fork() 时"老老实实"复制了父进程的全部物理页面(不使用 COW),会有怎样的浪费(1 分)?COW 如何避免这种浪费(1 分)?

(4)某进程的虚拟地址空间使用了 4 级页表(每级 4KB,页面 4KB)。fork() 时,假设该进程有 1000 个已分配的物理页面(对应 1000 个虚拟页),其中 800 个分布在低地址(0x0000~0x007F…),200 个分布在高地址(0x7FFF…)。请估算:fork() 使用 COW 后,在不触发任何写入的情况下,内核需要为新子进程分配多少字节的新物理内存来存放页表结构本身(不计物理数据页面)(3 分)。

考点:fork() 的内存管理机制、COW、页表结构空间开销

来源章节:第 5 章(内存管理之 COW)与第 3 章(进程创建)

完整解答过程

(1)fork() 的内存管理工作

  1. 复制页表结构:为子进程创建新的顶级页表(PML4),并逐级复制所有已使用的中间级页表(PDPT、PD、PT)
  2. 复制 VMA(Virtual Memory Area)结构:复制父进程的虚拟地址空间描述信息(代码段、数据段、堆、栈、mmap 区域等的起止地址和属性)
  3. 将父子进程的数据页面标记为 COW(写时复制):父进程和子进程的所有可写页面被标记为只读,并设置 COW 标志位
  4. 共享只读页面:代码段等只读页面继续被父子进程直接共享(无需 COW 标记)

(任写三项即可)

(2)COW 下的页表指向

fork() 刚返回后:父子进程的页表项指向同一组物理帧(共享物理页面)。这些页面的页表项中的写权限位(Writable bit)被清除(标记为只读),并且设置 COW 标记。

这意味着:父子进程都可以读取这些页面,但一旦任何一方尝试写入,硬件触发写保护异常,内核介入执行 COW 复制。

(3)fork() + execve() 的浪费与 COW 优化

无 COW 的浪费:如果 fork() 时完整复制了父进程的全部物理页面(假设 1000 个页面 ≈ 4MB),然后子进程立即 execve() 加载新程序——这些刚复制的 4MB 页面全部被丢弃(execve() 用新程序的地址空间替换旧地址空间),白白浪费了 4MB 的拷贝时间和内存分配。

COW 优化:fork() 时不复制物理页面,只标记 COW。当 execve() 被调用时,内核发现子进程要替换整个地址空间,直接释放子进程对父进程共享页面的引用(无需复制任何页面),避免了"复制后立即丢弃"的浪费。

(4)页表结构的物理内存估算

子进程需要复制全部页表结构(而不复制数据页面)。

4 级页表的扇出:每级 512 项(4KB ÷ 8B/项 = 512)。

覆盖的虚拟地址范围:

  • 低地址 800 页(0x0000…):这些页需要完整的 4 级路径
  • 高地址 200 页(0x7FFF…):独立的高地址路径

各级页表数量估算

低地址区域(800 页):

  • PML4:1 页(必然)
  • PDPT:800 页需要几个 PDPT 项?每个 PDPT 项覆盖 512 × 512 × 4KB = 1GB 范围。低地址 800 页 ≈ 800 × 4KB = 3.2MB,远小于 1GB。所以只需 1 个 PDPT 页表(1 项用于索引 PD)。
  • PD:每个 PD 项覆盖 512 × 4KB = 2MB。3.2MB ÷ 2MB = 2 → 即 1 个 PD 页表包含了 2 个有效项。
  • PT:800 页 ÷ 512(每 PT 表项)= 约 2 个 PT 页表(每 PT 最多映射 512 页)。

低地址需要:PML4(1) + PDPT(1) + PD(1) + PT(2) = 5 页

高地址区域(200 页):
同理,高端地址在 PML4 中是不同的条目 → PML4(已算过) + PDPT(1) + PD(1) + PT(1) = 3 页(PML4 复用)

高地址需要:PDPT(1) + PD(1) + PT(1) = 3 页

合计:低地址 5 + 高地址 3 = 8 页 = 8 × 4KB = 32KB

:大约需要分配 32KB 的物理内存用于页表结构本身。

讨论:实际还可能有更多 VMA 区域(堆、栈、mmap 区域、vdso 等),每个都需要独立的页表路径,实际开销会略大于此估算值。但相较复制 1000 个数据页面(4MB),页表复制的开销(约 32KB)可忽略不计,这也体现了 COW + 多级页表的协同优势。


答案速查表

题号 考点 核心答案
1 银行家算法 安全状态:<P1,P3,P0,P2,P4>;Request₁(1,0,2) 可分配
2 分段地址转换 (0,250)→2350;(1,150)→3650;(2,600)→越界;(3,400)→7200
3 分页地址转换 0x2A3C→0x1A3C;0x1120→0x7120;0x54A8→0x24A8
4 FCFS/SJF/HRRN FCFS平均周转15.25;SJF平均14.25;HRRN平均14.25
5 RR时间片轮转 平均周转10.25ms,平均等待5.75ms
6 动态分区分配 三种算法均成功分配,分配路径不同
7 页面置换 FIFO缺页15次(75%);LFU缺页13次(65%);LRU缺页12次(60%);OPT缺页9次(45%)
8 磁盘调度 FCFS=640;SSTF=236;SCAN=331;C-SCAN=382
9 死锁检测 存在死锁,P1~P4全部死锁
10 CHS/LBA转换 总容量1,032,192扇区;CHS(100,3,20)→LBA=50,608;LBA500000→CHS(992,0,33)
11 多级页表地址翻译 每级9位×4级+12位偏移;最坏5次内存访问;最短1周期/最长50周期;COW写时复制;节省内存但增加访存次数
12 TLB与缓存延迟 TLB覆盖256KB;平均延迟3.9周期;ASID机制避免全量TLB刷新
13 倒排页表 100万项(4GB物理内存);大小∝物理内存非虚存;哈希加速查找;链地址法处理冲突
14 大页与TLB 4KB覆盖256KB/2MB覆盖128MB/1GB覆盖64GB;2MB页只需3级页表;大页:减少TLB miss但增加内部碎片
15 fork()与COW 复制页表结构(~32KB)不复制数据页面;COW标记只读;execve()避免无效复制
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐