评价标准

  • 缺页发生频率少,防止系统发生抖动(Thrashing)
  • 算法本身的复杂度小

驻留集(Resident Set)

  • 进程当前在内存中的物理页帧集合
  • 固定驻留集 + 局部置换:每个进程分配固定页帧数,只在本进程内置换
  • 可变驻留集 + 全局置换:动态调整驻留集大小,系统范围内置换

重点 固定驻留集算法

FIFO(先进先出)

  • 淘汰最早进入内存的页面(队列实现:队首淘汰,队尾插入)
  • 实现简单,无需额外硬件支持,但效果差
  • Belady 异常:分配更多页帧反而缺页更多
  • 演算示例(访问串 7,0,1,2,0,3,0,4,2,3,0,3,2,驻留集=3):
    • 7→0→1 依次入内存;访问 2 时缺页,淘汰最早进入的 7
    • 访问 3 时缺页,淘汰当前最早的 0 … 依次类推

OPT(最佳置换)

  • 淘汰未来最长时间内不再访问的页面(或永不访问的页面)
  • 理论上缺页中断次数最少
  • 不可实现(未来访问串未知)
  • 价值:作为理论参照标准(性能下界标尺)

重点 LRU(最近最久未使用)

  • 淘汰过去最长时间未被访问的页面(” 往后看未知,往前看已知 ”)
  • 栈式算法:驻留集大小为 M 时的页帧集合 ⊆ 驻留集为 M+1 时的页帧集合
  • 无 Belady 异常(栈式算法可证明,驻留集增大时缺页次数一定不增)
  • 实现:每页帧配计数器,访问时清零、其余加一,淘汰计数值最大的页
  • 性能好,但实现代价高(需额外硬件支持)

Clock(时钟算法 / 第二次机会)

  • 物理页帧组成循环链表(钟面),指针(钟针)在其中旋转
  • 页表增加访问位,循环检查:
    • 访问位 = 1 → 置 0,指针下移(给第二次机会)
    • 访问位 = 0 → 淘汰
  • 若全部访问位均为 1,转一圈后全部变 0,回到原点淘汰
  • 性能接近 LRU,实现简单(仅需一位访问位)

NRU(最近未使用算法)

  • 结合 FIFO 和 LRU 思想:页表项增加使用位,定时清零
  • 淘汰优先级(同时考虑使用位和修改位):
    1. 使用位=0,修改位=0(最优先,无需回写外存)
    2. 使用位=0,修改位=1(需回写)
    3. 使用位=1,修改位=0
    4. 使用位=1,修改位=1(最后)
  • 优先淘汰修改位=0 的页面:避免回写开销

动态驻留集算法

程序形态

  • 局部性形态:程序在一段时间内工作于某个局部热点(工作集)
  • 阶段转换形态:执行热点从工作集 A 跳转到工作集 B

工作集模型(Working Set, WS)

  • 设置 δ 间隔(delta window),每经过 δ 次页面访问,淘汰在该间隔内未被访问的页面
  • 驻留集大小随工作集动态变化
  • 实现:每页配计数器,访问时清零、其余加一;淘汰计数器值 = δ 的页
  • 开销大(每页一个计数器)

SWS(Sampled Working Set)

  • 改进 WS:页表项中记录当前时间戳(访问时写入时钟值)
  • 操作系统定时检查:当前时钟值 - 页表项时间戳 > δ → 淘汰
  • 无需额外计数器,硬件消耗仍较大

实用 OS 策略:SWS + 延迟清除

  • 自由列表(Free List):修改位=0,页面内容无需回写
  • 修改列表(Modified List):修改位=1,待回写
  • 修改链过长或自由链过短时,将修改链页面回写外存后移至自由链
  • 缺页中断时,从自由链直接分配物理页帧(数据可覆盖)
  • 关键优化:若自由链/修改链中的页面被再次访问,只需将合法位置 1,无需从外存重新加载

缺页频率控制(PFF)

  • 动态调整进程的驻留集大小,防止抖动
  • 驻留集 < 工作集 → 频繁抖动
  • 驻留集 >> 工作集 → 内存浪费

多级页表

  • 为什么需要:32 位系统,页大小 4K(2¹²),页表项 4B → 页表需 2²² = 4MB 连续物理空间。页表本身也可分页存储,避免大块连续分配
  • 二级页表结构(10+10+12)
    • 页内偏移:12 位
    • 二级页号(内层页表):10 位
    • 页目录号(一级页表):10 位
  • 地址转换:先查页目录 → 获二级页表地址 → 查二级页表 → 获物理帧号 → 拼接偏移
  • 计算示例:逻辑地址空间 2¹⁶ 个页(64MB),页大小 1K(10 位偏移),页表项 2B:
    • 每页可存放页表项数:1K / 2B = 2⁹ = 512 项(9 位索引)
    • 页目录号位数:26 - 10 - 9 = 7 位 → 128 项
  • 64 位系统使用哈希页表(逻辑页号作哈希值,链表解决冲突)

最佳页面大小推导

假设进程平均大小 S 字节,页面大小 P 字节,页表项 1B:

  • 页表开销:S/P
  • 内部碎片:P/2(每页平均浪费半页)
  • 总开销:C(P) = S/P + P/2
  • 求导得最优:P = sqrt(2S)
  • 实际系统据此选择页大小(如 4K)

比较

算法性能实现开销Belady 异常类别
OPT最优(理论)不可实现局部
LRU无(栈式算法)局部
Clock较好局部
NRU较好局部
FIFO一般最低局部
WS全局
SWS较高全局