不能单独用std::queue实现fifo页面置换,因其无o(1)查页功能且无法同步维护驻留状态;必须配合std::unordered_set,并严格保证二者操作原子对齐。

直接用 std::queue 实现 FIFO 页面置换,命中率一定算错——它不支持 O(1) 查页是否存在,也无法自动清理已淘汰页的驻留状态。
为什么 std::queue 单独用不了 FIFO 置换
缺页判断必须在 O(1) 内完成,而 std::queue 没有 find() 成员函数;若手动遍历判断,单次查找退化为 O(m),m 是物理帧数,m=64 时每次访问多做 64 次比较;更严重的是:队列里残留已淘汰页号,inMemory.find(page) 会失败,导致本该命中的访问反复触发缺页。
- 只调用
pageQueue.push(page)却漏掉inMemory.insert(page)→ 后续所有访问都判为缺页 - 淘汰时只
pageQueue.pop()但没inMemory.erase(victim)→ 集合中残留脏数据 - 误写成
if (pageQueue.find(page) != pageQueue.end())→ 编译失败,std::queue根本没有find方法
必须同步维护 std::queue 和 std::unordered_set
前者管“谁该被淘汰”,后者管“谁还在内存里”,二者操作必须原子对齐,否则状态立刻失真。
- 声明两个结构:
std::queue<int> pageQueue</int>和std::unordered_set<int> inMemory</int> - 每次访问
page前,只查inMemory.find(page) != inMemory.end(),O(1) 稳定 - 命中:不碰
pageQueue,不增pageFaults - 缺页:先
pageFaults++,再检查pageQueue.size() == frameCount;若满,则int victim = pageQueue.front(); pageQueue.pop(); inMemory.erase(victim); - 最后统一执行
pageQueue.push(page); inMemory.insert(page);
手写循环数组时 cur 指针的边界陷阱
cur 不是“当前最老页索引”,而是“下次应覆盖的帧下标”,它的更新必须受物理帧数 frameCount 严格约束,且仅在缺页且内存已满时发生。
- 分配数组必须是
std::vector<int> frames(frameCount, -1)</int>,大小不能多也不能少 -
cur初始化为 0,所有更新必须形如cur = (cur + 1) % frameCount,禁用cur++后 if 判断重置 - 内存未满阶段(即
frames中还有-1)绝对禁止移动cur,否则最早装入页无法被优先淘汰 - 淘汰前必须读
frames[cur]获取待换出页号,并同步从inMemory中erase;装入后立即写frames[cur] = page
命中率分母必须是总访问次数,不是别的
操作系统定义明确:命中率 = (总访问次数 - 缺页次数) / 总访问次数。这个“总访问次数”就是输入序列原始长度,一个都不能少,包括第一次装入前的所有访问。
- 误把前
frameCount次(填满内存)过滤掉统计 → 分母变小,命中率人为抬高 - 对访问序列去重后再计数 → 在周期性序列(如
0 1 2 0 1 2)中误差爆炸 - 输出写成
hit_count / (totalAccesses - pageFaults)→ 数学定义错误,不是命中率 - 哪怕
frameCount == 1,首次访问也计入缺页,分母仍为完整序列长度
最容易被忽略的一点是:cur 在循环数组中代表“下一个淘汰位”,不是“当前最老页位置”;而 FIFO 的“先进”永远指页面**进入内存的时间戳**,不是它在原始访问序列里的下标位置——交叉访问(如 0 1 2 0 1 3)下,仅靠序列顺序无法还原真实驻留状态。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











