OS2️⃣内存管理:页面置换算法
页面置换
- 发生缺页中断时,OS 需要在内存中选择一个页面淘汰,从磁盘文件中载入新的页面。
- 若页面在内存驻留期间被修改过(modified bit = 1),则必须将脏页写回磁盘,否则直接被新页面覆盖即可。
1、局部
- 局部性访问:
- 进程运行期间,只访问少部分页面(而不是全部),因此只有少数页表项会被反复读取。
- 过去最近被频繁访问(使用)的页面,在将来很有可能被再次访问。
- 局部页面置换算法:根据局部性原理,预测短期内较少使用的页面换出,尽可能减少缺页中断次数。
1.1、最优
- 思想:淘汰在将来最久会被使用的 page。
- 发生缺页中断时,对于每个在内存中的页(page),计算并标记 page 在下次被访问前需执行的指令数。
- 置换标记最大的 page。
- 说明:
- 此算法是一种无法实现的理想情况,因为 OS 无法确定每个 page 将被访问的时机。
- 可作为其它算法的性能评价依据。
1.2、最近未使用(NRU)
Not Recently Used
-
实现:
- 为每个 page 设置 2 个状态位(访问位 R、修改位 M)。
- 发生缺页中断时,OS 检查所有 page 并根据状态位进行相应处理。
-
说明:性能不是最优,但可用。
R 位 M 位 缺页中断的处理 第 0 类 0 0 被置换 第 1 类 0 1 清除 M 位(00) 第 2 类 1 0 清除 R 位(00) 第 3 类 1 1 清除 R 位(01)
(不清除 M 位,作为 page 是否需要写回磁盘的依据)
1.3、先进先出(FIFO)
First-In First-Out
- 实现:淘汰在内存中驻留最久的 page。
- 维护一个在内存中的 page 的链表(队列)。
- 发生缺页中断时淘汰表头的 page,新 page 加入到表尾。
- 说明:
- 性能差。
- 淘汰的页面可能是被经常访问的页面。
- 会产生 belady 现象:
- belady 现象:增加分配的物理页(page frame),缺页率不减反增。
- 原因:FIFO 仅考虑 page 驻留时间,忽略了进程访问 page 的特点。
1.4、第二次机会
second chance
(对 FIFO 策略的优化)
- 实现:发生缺页中断时,检查表头 page 的 R 位。
- 0:淘汰。
- 1:清除 R 位并将 page 移到表尾,重复此过程直到淘汰一个页面。
- 说明:若所有 page 都被访问过(R = 1),退化为 FIFO 算法。
1.5、时钟
clock
(对 FIFO 数据结构的优化)
- 实现:维护一个在内存中的 page 的环形链表,指针指向最老的页面。发生缺页中断时检查指针指向 page 的 R 位。
- 0:淘汰
- 1:清除 R 位并将指针前移一位,重复此过程直到淘汰一个页面。
- 说明:可参考 NRU 和 second chance 算法,结合 M 位优化淘汰策略。
1.6、最近最少使用(LRU)
Least Recently Used,
(最优算法的一个较好近似)
实现:根据局部性原理,淘汰最近最少使用的 page。
- 记录每个 page 被访问次数(e.g. 维护一个在内存中的 page 的链表,表头是最近访问次数最多的 page,表尾反之)
- 发生缺页中断时,淘汰最近使用次数最少的 page。
1.7、最不常用(LFU)
Least Frequently used
- 实现:淘汰访问次数最少的 page。
- 为每个 page 设置一个访问计数器。
- 发生缺页中断时,淘汰访问次数最少的 page。
- 说明:LRU 侧重于最近访问次数,LFU 侧重于总访问次数。
2、全局
局部页面置换算法的前提:局部性原理。
- 若局部性原理不成立,局部页面置换算法没有意义。
- 若局部性原理成立,需要进行定量分析——工作集模型。
2.1、相关概念
2.1.1、page
调页
- 请求调页:page 在进程需要时被调入,而不是预先装入。
- 预先调页:在进程运行之前,预先装入 page。
缺页
- 缺页中断:进程所访问的 page 不在内存中,需要由 OS 从磁盘中调入。
- 颠簸(抖动):进程每执行几条指令就发生一次缺页中断,即需要频繁地在内存和外存之间交换页面,影响进程的运行速度。
2.1.2、工作集
进程执行过程中的固有性质
- 工作集:进程当前正在使用的 page 的集合,随时间而变化。
- 符号:
W(t, k)
- 含义:在任意时刻 t,进程最近 k 次内存访问中包含的 page 的集合。
- 符号:
- 工作集模型:按照预先调页的思想,在进程运行前预先将其工作集装入内存。
2.1.3、常驻集
取决于 OS 分配给进程的 page frame 数目、采用的页面置换算法。
概念:进程当前实际驻留在内存中的 page 的集合。
- 若常驻集 <= 工作集:说明分配给进程的 page frame 太少,无法包含整个工作集,进程产生抖动。
- 若常驻集 >= 工作集:说明进程需要的 page 都在内存中,进程不会产生抖动。
2.2、页面置换算法
2.2.1、思路
思路:发生缺页中断时,淘汰一个不在工作集中的 page。
- 前提:预先确定 k 值,从而唯一确定工作集。
- 说明:计算工作集的开销大,需要在程序执行期间及时计算。
近似方法:考虑执行时间 delta(代替内存访问次数 k),每个进程只需计算自己的执行时间。
- delta:工作集窗口,表示一个定长的页面访问的时间窗口。
W(t, delta)
:在任意时刻 t 之前的 delta 窗口中,进程访问的 page 的集合。- 示例:
- 考虑次数:工作集 = 进程过去 100 万次内存访问所使用的 page 的集合。
- 考虑时间:工作集 = 进程过去 10 ms 中内存访问所使用的 page 的集合。
2.2.2、工作集页面置换算法
思想:在工作集窗口滑动过程中,淘汰不在工作集中的 page 并淘汰(而不是等到缺页中断)。
2.2.3、缺页率置换算法
思想:可变分配策略,即常驻集大小可变。
- 进程刚开始运行:根据程序大小分配一定数目的 page frame。
- 进程运行过程中:动态调整常驻集大小。
实现:缺页率算法
- 缺页率 = 缺页次数 / 内存访问次数
- 若缺页率增大,则增加常驻集大小,反之减少。
3、小结
3.1、页面置换算法
说明 | |
---|---|
最优 | 理想情况,无法实现,可作为基准 |
NRU | LRU 的粗略近似 |
FIFO | 可能淘汰重要 page |
第二次机会 | FIFO 的改进 |
时钟 | 现实 |
LRU | 优秀,但难以实现 |
NFU | LRU 的粗略近似 |
老化 | LRU 的有效近似 |
工作集 | 实现开销大 |
工作集时钟 | 好的有效算法 |
3.2、分配策略
- 局部:为每个进程分配固定的内存片段。
- 全局:在可运行进程之间,动态分配 page frame。