单独用std::queue实现FIFO页面置换必然出错,因其无O(1)查找能力,无法判断页是否驻留,导致命中全判缺页、淘汰错位、状态不同步;正确做法是std::queue管理入序,std::unordered_set同步维护驻留页集,二者操作严格对齐。

单独用 std::queue 实现 FIFO 页面置换,命中率一定错——它根本没法快速判断页是否已在内存中,所有“命中”都会被当成“缺页”,结果完全不可信。
为什么 std::queue 单独用不了 FIFO 置换
因为 FIFO 调度有三个原子动作:查驻留、决定淘汰、更新状态。而 std::queue 只做第二步(顺序管理),不做第一步(O(1) 查存在)和第三步(同步清理)。常见后果包括:
- 查命中写成
q.find(x)→ 编译失败,std::queue根本没有find成员函数 - 退而求其次遍历队列判断存在 → 时间复杂度升为 O(m),m=64 时单次查找多 64 次比较
- 淘汰页后只调
q.pop(),不删in_memory.erase(old)→ 集合残留脏数据,后续再访同一页面仍报缺页 - 插入新页时只
q.push(page),漏掉in_memory.insert(page)→ 所有后续访问都查不到,全判缺页
std::queue + std::unordered_set 同步操作要点
这两个结构必须像齿轮一样咬合转动,每一步增/删都成对出现:
- 查命中:只用
in_memory.find(page) != in_memory.end(),绝不碰q - 缺页且内存未满:先
q.push(page),再in_memory.insert(page) - 缺页且内存已满:先取
int old = q.front(),再q.pop(),紧接着in_memory.erase(old),最后q.push(page)和in_memory.insert(page) - 任何时候都不能让
q.size()和in_memory.size()不一致 —— 这是状态错位的直接信号
循环数组手写 FIFO 时 cur 下标怎么不出界
手写循环数组比用 STL 更容易崩,关键在 cur 的更新逻辑和内存分配:
立即学习“C++免费学习笔记(深入)”;
- 数组必须严格按物理块数
m分配:vector<int> frames(m, -1)</int>或new int[m],不能是m+1或更大 -
cur仅在“缺页且frames已满”时才更新:cur = (cur + 1) % m,填满前的所有装入都不动cur -
cur表示“下次要覆盖的位置”,不是“当前最老页位置”——最老页永远在frames[cur],这点极易混淆 - 初始化
cur = 0后,若没加% m就直接cur++,越界写入会覆盖相邻变量,调试极难定位
命中率分母为什么必须是总访问次数
操作系统定义明确:缺页率 = 缺页次数 / 总页面访问次数。这个“总次数”就是输入序列长度 n,一个都不能少:
- 序列
7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1共 17 次访问 → 分母就是 17 - 前 3 次访问(填满内存)若被跳过统计 → 分母变小,命中率人为抬高
- 把重复页号去重再算分母 → 在周期性序列(如
0 1 2 0 1 2)中误差爆炸 - 输出写成
hit / (n - cnt)(用命中数除以非缺页数)→ 数学定义错误,不是缺页率
真正容易被忽略的是:FIFO 的“先进”指进入内存的时间戳,不是访问序列里的下标位置;而第一次装入就触发 page fault,这事从 OS 启动那一刻就开始计数了。


















