【操作系统导论】内存篇——页面置换

一. 机制

在硬盘上开辟一部分空间用于物理页的移入/移出,在 OS 中称为交换空间 (swap space)

假设 OS 以页大小为单元读取/写入交换空间。为此,OS 需要记住给定页的硬盘地址。

交换空间的大小是非常重要的,它决定了系统在某一时刻能够使用的最大内存页数。

存在位

回忆一下内存引用:

  • 硬件首先从虚拟地址获得 VPN;

  • 检查 TLB 是否命中,如果命中,则获得最终的物理地址并从内存中取回;

  • 如果 TLB 未命中,则硬件在内存中查找页表(使用页表基址寄存器),通过 VPN 查找该页的页表项 PTE 作为索引;

  • 如果页有效且存在于物理内存中,则硬件从 PTE 中获得 PFN,将其插入 TLB,并重试该指令,这次产生 TLB 命中。

但是,当硬件在 PTE 中查找时,可能发现页不在物理内存中!

硬件通过页表项中的一条新信息,即 存在位 (present bit),来判断页是否在物理内存中。

如果存在位为 1,则该页存在于物理内存中;如果存在位为 0,则页不在内存中,而在硬盘上。

页错误

访问不在物理内存中的页,这种行为通常被称为 页错误 (page fault)

页错误由操作系统的页错误处理程序 (page-fault handler) 来处理,即:操作系统需要将该页交换到内存中。

那么,问题来了:操作系统如何知道所需的页在哪儿?

操作系统可以用 PTE 中的某些位来存储硬盘地址,这些位通常用来存储像 PFN 这样的数据。

  • 当 OS 接收到页错误时,它会在 PTE 中查找地址,并将请求发送到硬盘,将页读入内存;

  • 当硬盘 I/O 完成时,OS 会更新页表,将此页标记为存在,更新 PTE 的 PFN 字段以记录新获取页的内存位置,并重试指令;

  • 下一次重新访问 TLB 还是未命中,然而这次该页在内存中,因此会将页表中的地址更新到 TLB 中; (也可以在处理页错误时更新 TLB 以避免此步骤)

  • 最后,重试该指令,在 TLB 命中,得到最终的内存物理地址,并获取所需的数据或指令。

置换时机

一种简单的方法:

等到内存满了以后,OS 执行页面置换流程,替换(踢出)一个页为其他页腾出空间。

但是,这有点不切实际的,因为操作系统可以 更主动地预留一小部分空闲内存

预留少量空闲内存的方法:

通过设置 高水位线(High Watermark)低水位线(Low Watermark),来帮助决定置换时机。

  • 当 OS 发现有少于 LW 个页可用时,后台线程开始释放内存,直到有 HW 个可用物理页;

  • 该后台线程称为 交换守护进程页守护进程,在释放完一些内存后,它会进入休眠状态;

  • 系统可能会把多个要写入的页 聚集分组,同时写入到交换区间,从而提高硬盘的效率。

超额请求

当进程的内存需求超出了可用物理内存,操作系统应该怎么办?

在这种情况下,系统将不断地进行换页,这种情况有时被称为 抖动(thrashing)

一些早期的操作系统有一组相当复杂的机制,以便在抖动发生时检测并应对。

例如,给定一组进程,系统可以决定不运行部分进程,希望减少的进程工作集(它们活跃使用的页面)能放入内存,从而能够取得进展。这种方法通常被称为 准入控制(admission control), 即少做工作有时比多做工作效果更好,这是我们在现实生活中以及在现代计算机系统中经常遇到的情况。

目前的一些系统采用更严格的方法处理内存过载。

例如,某些版本的 Linux 会运行 “内存不足的杀手程序(out-of-memory killer)”。这个守护进程选择一个内存密集型进程并杀死它;虽然成功地减轻了内存压力,但这种方法可能会遇到问题,例如,如果它杀死 X 服务器,就会导致所有需要显示的应用程序不可用。

二. 策略

最优策略

最优策略 OPT 的思路是:置换出内存中在最远将来才会被访问到的页面。

因为我们无法预测未来,因此无法实现。

简单策略

简单的页面置换策略包括:FIFO随机策略

  • FIFO 替换策略:

    页在进入系统时,简单地放入一个队列;当发生替换时,队列头部的页被踢出。

  • 随机替换策略:

    在内存满的时候,随机选择一个页进行替换。

局部性原理

页面替换策略可以考虑的历史信息有 频率(frequency)近期性(recency)

  • 如果一个页被访问了很多次,也许它不应该被替换,因为它显然更有价值;

  • 如果一个页在近期被访问过,也许再次访问的可能性很大。

这一系列的策略是基于人们所说的 局部性原则(principle of locality)

基于局部性原理,诞生了*“最不经常使用”策略(LFU)* 和 “最近最少使用”策略(LRU)

clock 策略

clock 策略 是一种 LRU 的近似算法,是一种性能和开销较均衡的算法。由于 LRU 策略需要较多的硬件支持,采用 clock 策略只需相对较少的硬件支持。

clock 的实现方法:

  • 为每个页面设置一个「访问位」和一个「修改位」,将内存中的页面通过指针链接成循环队列;

  • 当某页被访问时,其「访问位」置为 1,当页面数据修改时,其「修改位」置为 1;

  • 从当前位置开始扫描,查找第一个(0,0)的帧用于替换;

  • 若第一轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换,并将所有扫描过的帧「访问位」置为 0;

  • 若第二轮扫描失败,则重新扫描,查找第一个(0,0)的帧用于替换;

  • 若第三轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。

由于第二轮已将所有帧的访问位设为 0,因此经过第三轮、第四轮扫描一定会有一个帧被选中,因此该 clock 置换策略选择一个淘汰页面最多会进行四轮扫描。

你可能感兴趣的:(#,操作系统,linux)