《现代操作系统》03章 存储管理(三)
0 前文
《现代操作系统》03章 存储管理(一)
《现代操作系统》03章 存储管理(二)
4 页面置换算法
前面讲到,当访问的内容不在内存中时会产生缺页中断,在缺页中断的处理中要完成页面置换。当然并不是只有在虚拟内存管理中才需要页面置换算法,在高速缓存中也会出现页面置换,本节讲解几个重要的置换算法。
在所讨论的置换算法中都存在一个问题:被置换的页面只能是本进程的页面?被置换的页面可以是其他进程的页面?
4.1 最优页面置换算法
概念:
这是一个不能实际运行的算法,但是可以作为其他置换算法的考核标准(相当于天花板的存在)。每个页面都被做了标记,这个标记的含义是该页面被首次访问前所执行的指令数(这很显然是一个先验数据,即对特定的程序在特定的输入下运行并进行页面跟踪才能得到的数据,实际运行的操作系统对于这个值是不可知的),置换时选择标记值最大的页面进行置换,目的是减少缺页中断的发生。
作用:
此算法起一个标杆作用,当一个页面置换算法的性能与此算法及其相近时,那么这个算法可以认为是一个高效的算法。并且假如置换算法与该算法性能相差很小的情况下就没必要再花费更大的功夫去缩小那一点点性能差值了。
4.2 最近未使用页面置换法(NRU)
前提:
系统为每个页面设置两个状态位(存在于页表中,回看3.3),访问位(读或写都被置位)、修改位(dirty bit 仅写入时被置位),这两个位一旦被硬件置位将一直保持直到被系统复位。
无硬件置位的软解决:
当启动一个进程时 将所有页面都标记为不在内存,一旦访问一个页面就引起缺页中断
首次访问引起缺页中断时 操作系统设置软访问位为1,分配页框,并设置为ReadOnly模式
页面修改引发缺页中断时 操作系统设置修改位为1,并设置为Read/Write模式
算法思路:
进程启动时,所有页面的访问位、修改位均置0
访问位被定期清零(如时钟中断时),以区分频繁访问的页面和长时间未被访问的页面
发生缺页中断时,操作系统分析页表项中的两个位,两个位可以将页面分为四类
类别 | 访问位 | 修改位 |
---|---|---|
0类 | 0 | 0 |
1类 | 0 | 1 |
2类 | 1 | 0 |
3类 | 1 | 1 |
算法随机从 类编号最小 且 非空类 中挑选一个页面淘汰
NRU(Not Recently Used)的隐含之意是淘汰没有被访问的已修改页面(需要磁盘写入)比淘汰一个被频繁使用的“干净”页面要好,虽然性能不是最好的算法,但是也够用
4.3 先进先出页面置换算法(FIFO)
该算法思想简单,但并不实用
FIFO即先进先出的队列,操作系统维护一个定长的队列(当前内存中的页表项),当发生缺页中断,淘汰掉表头即最早加入列表的页面,将新的页面放在表尾,这就造成了经常淘汰掉使用频繁的页面(固定的淘汰机制下众页面平等)
很少使用纯FIFO的淘汰算法
4.4 第二机会页面置换算法
这是一个FIFO置换算法的改进,顾名思义,给表头的表项一次证明自己有用的机会。
算法思路:
发生缺页中断时,检查表头页表项的访问位,若该位为0则直接淘汰,若该位为1则将该位复位并把此页表项放置表位,继续检查表头,直到找到可淘汰的页面(若所有页面都被访问过则最终淘汰的还是表头)
缺点:总是修改链表,降低效率
4.5 时钟页面置换算法
此算法是第二次机会算法的再改进,将直链表修改为环形链表(如钟表一般),这样任何一个节点都可以是表头或表尾,也就没必要将节点移来移去了,只需要一个如表针的指针转圈依次指向节点即可,指针在缺页中断发生时指向最老页面的页表项。
4.6 最近最少使用页面置换算法
核心思想:
缺页中断发生时置换未使用时间最长的页面,称为LRU(Least Recently Used)置换算法。但这就要不停地更新链表把最新访问的页面放到表头,这是一项不小的开销
硬件实现:
方法一 设计一个硬件计数器(64bit),每执行一条指令该计数器加一,访问页面时将计数器的值放入页表项对应的区域,缺页中断时页表中该值最小的页表项即最近最少使用,淘汰即可
方法二 若机器中有n个页框,使用硬件维护一个初值为0的n*n矩阵,当访问页框k时,将k行全部置1,k列全都置0,缺页中断发生时,二进制值最小的行即最近最少使用的页面
4.7 软件模拟LRU
硬件并不是所有机器中都具备,需要通用性更强的软件来实现
算法一 NFU:
NFU(Not Frequently Used)即最不常用算法,该算法给每个页面关联一个计数器,初值为0,每次时钟中断时,操作系统扫描所有页面并将页表项的访问位加到各自的计数器上,缺页中断时淘汰计数器值最小的页面。该算法有一个问题,新页面的计数器值可能总是低于老页面的计数器值,可能有用的新页面被误淘汰
算法二 老化算法:
该算法是对NFU的一个改进算法,改进如下:访问位在加入计数器前,计数器的值右移一位;访问位的值加在计数器的左端;计数器的大小较小(若时钟中断周期20ms,则仅需8bit)。发生缺页中断时,计数器值最小的页面被淘汰
4.8 工作集页面置换算法
工作集(working set)
多数进程在某运行时刻运行时只访问较少部分的页面,这个当前正在使用的页面集合称为 工作集。
例如:任意时刻 t 都存在一个集合,它包含所有最近 k 次(例如K取1000万)访问过的页面,即w(k,t),w(k,t)是k的单调非减函数,并且w(k,t)存在上限,注意:这仅仅是一种工作集的定义方式,并不是唯一的。
可以看到,当k较大时,k在一定范围内变化工作集的大小是基本不变的,因为工作集是随时间缓慢变化的
意义
在进程运行时,预先将工作集调入内存,大大减少缺页中断频率,当程序发生高频缺页中断时称为 颠簸(thrashing)
工作集模型(working set model)
分页系统设法跟踪工作集,确保在程序运行前将其工作集调入内存,该方法也称为 预先调页 ,工作集会随时间而变化。
如何维护工作集是一个问题,因为这要占用系统的软硬件资源,一种是使用移位寄存器来记录最近k次访问的页面号,但寄存器的维护开销大;另一种方法改变了工作集的定义方式,将最近k次改为最近一段时间(10ms、20ms等),这个时间是针对每个进程的实际运行时间而言
置换算法
核心思想:缺页中断发生时,置换掉不在工作集中的页面
使用到的页表项内容:访问位、上次使用该页面的近似访问时间
前提:使用硬件置位访问位、修改位,每个滴答时钟周期会清除一次访问位
算法流程:下图所示
4.9 工作集时钟页面置换算法
可以看到上一种算法要扫描整个页表才能完成置换,因此上一种算法也是较为耗时的,本算法是对上一算法的改进,与之前的时钟置换算法非常类似,这种算法实现简单且效率高而应用广泛。
置换算法
使用到的页表项内容:访问位、修改位、上次使用该页面的近似访问时间
算法流程:下图所示
4.10 小结
算法 | 注释 |
---|---|
最优算法 | 不可实现,作为理论基准 |
NRU(最近未使用) | LRU的粗糙近似 |
FIFO(先进先出) | 可能抛弃重要页面 |
第二次机会算法 | 比FIFO有大的改善 |
时钟算法 | 现实的 |
LRU(最近最少使用) | 很优秀,实现困难(需要硬件) |
NFU(最不经常使用) | LRU相对粗糙近似 |
老化算法 | 非常近似LRU的有效算法(推荐) |
工作集算法 | 实现开销大 |
工作集时钟算法 | 好的有效算法(推荐) |
X 往期文章
Python+OpenCV+imutils的简单图片处理(放缩、翻转、旋转、灰度RGB提取)
如果文中有误,还请在评论区指正。这里是海小皮,我们一同进步!!!!