- 什么是页面置换算法呢?
“进程运行时,若其访问的页面不在内存而需将其调入,但内存已无空闲空间时,就需要从内存中调出一页程序或数据,送入磁盘的对换区,其中选择调出页面的算法就称为页面置换算法。
- 页面置换算法分为两类,一类为局部页面置换算法、一类为全局页面置换算法
一、最优页面置换算法
🌔 1、该算法的目标是什么?
-
当一个缺页中断发生时,对于保存在内存当中的每一个逻辑页面,计算在它的下一次访问之前,还需等待多长时间,从中选择等待时间最长的那个作为被置换的页面。
-
因为操作系统无法得知每个页面要等待多长时间以后才会再次被访问,所以这种算法无法在现实中实现,通过用作页面置换算法的一种评价标准。
-
发生缺页中断时,并不是页中的内容不存在,而是整个页不存在
🌔 2、通过一个案例来分析最优页面置换算法【假设知道未来程序的调用】
在时间为5的时候要导入页面e,此时可以判断出等待时间最长的为10-d,所以将其移动到外存中,先调入e。
二、先进先出算法
🌔 1、该算法的实现思路:
当需要置换时,选择在内存中驻留时间最长的页面淘汰,底层是用一个链表来维护的,记录了所有位于内存当中的逻辑页面。但是我觉得用队列来描述更好理解。
🌔 2、这里通过一个小案例来理解:
- 从零时刻a页面就存在内存中,之后是b >> c >> d。
- 当到了第五个时刻,需要调用e页面,但是此时内存中没有,就要通过我们这个先入先出算法来将其加载到内存中。
- 找到链表的表头,将a页面移动到外存中,再将e页面加载进来
- 在第七个时刻,再次调用a页面,还要将此时在内存中时间最长的页面移出去,所以b页面被移除
🌔 3、尽管这个算法比较简单,但是存在一定问题
这种算法性能较差,调出的页面有可能是经常访问的页面,并且会有 Belady现象,一般不会单独使用这种算法。
三、最久未使用算法(LRU)
🌔 1、算法实现思路:
- 当一个缺页中断发生时,选择淘汰最久未使用的那个页面。
- 它是最优页面置换算法的一个近似,一个为选择距离未来最久的,一个选择距离现在的最久
- 适用于程序的局部性原理,在这种原理的情况下,如果一个程序经常访问,那么通过这种算法一般情况下就不会将常驻内存中的程序移除内存
🌔 2、采用与先入先出案例相同的案例分析:
- 在时刻5调用内存中没有的页面,此时就要选择当前最久没有使用的页面,所以调出页面c,将页面e加载到内存中并未其分配帧号。
- 通过这种算法我们可以看到结果是相对比较好的,可以减少调入调出的次数
🌔 3、那么如何实现记录程序最近一次使用的序号呢?
(1)通过链表来记录,当调用一个新程序时,就将这个程序添加到链表的表头,当内存中剩余空间不足或即将不足时,就淘汰链表尾部的页面
(2)通过栈来记录,将最近的活动添加到栈顶,如果栈内部存在相同的活动就删除原来的记录,如果内存中接近空间不足时,就将栈底的活动移除内存
四、时钟页面置换算法
- Clock算法属于FIFO算法的一种改进,与LRU算法近似
🌔 1、该算法的实现思路:
- 需要用到页表项当中的访问位,当一个页面被装入内存时,把该位初始化为0。然后如果这个页面被访问(读/写),则把该位置为1【使用了这个页面就为1,没使用就为0】
- 把各个页面组织成环形链表(类似钟表面),把指针指向最老的页面 (最先进来)
- 当发生一个缺页中断时,考察指针所指向的最老页面,若它的访问位为0立即淘汰:若访问位为1,则把该位置为0,然后指针往下移动一格。如此 下去,直到找到被淘汰的页面,然后把指针移动到它的下一格。
🌔 2、这个环形链表的结构说明:
-
在内存中维护一个环形链表,用时钟位标记一个页面是否经常被访问
🌔 3、案例分析: -
首先要明确一个事情,对于这个 use bit 的改变完全是由硬件来实现的,不需要软件的参与
-
第二点,对于我们访问内存中已经存在的页面时,不需要移动指针
-
第三点,完成当前页面的导入后,要将指针移动到下一位
(1)假设现在内存中只能装载四个页面,所以前四个时刻不会发生置换中断
(2)在第五个时刻需要将页面e置换进来,指针从a页面的位置开始寻找use bit 为零的位置,找了一圈将所有页面的use bit 都变成0了,所以最后指针到a页面位置完成替换,然后指针移动一位。【查找的过程为先移动后置零】
(3)在第六个时刻又调用b页面了,所以硬件直接将use bit 置1,指针不动还在b页面位置
(4)在第七个时刻调用a页面,需要加载到内存中,开始寻找第一个use bit 为零的位置,当前位置为1,所以将b页面置零,寻找到c页面并且其use bit 为0,完成替换,移动指针
(5)以此类推 …
五、两次机会置换算法
- 属于时钟置换算法的一种改进,因为访问资源可能是读或写,所以当执行写操作后要释放资源,就要将数据写会外存,保证数据的正确性
- 设置一个脏位 dirty bit , 0 代表进程执行读操作,1代表进程执行写操作
🌔 1、通过usebit 和 dirty bit 来决定哪个页应该被置换出去
🌔 2、指针移动过程中的替换规则:
10 >> 00、01 >> 00、11 >> 01 >> 00 直接释放替换
🌔 3、案例分析:
- 上角标w代表写操作
- 总共完成三次置换:
- 对于只是加载到内存没有执行读写操作的直接释放,读过或写过的一次机会之后释放,正在读的一次机会后释放,正在写的两次机会之后释放
六、最不常用算法(LFU)
🌔 1、基本思路:
-
当一个缺页中断发生时,淘汰选择访问次数最少的页面
-
对每个页面设置一个访问计数器,每当一个页面被访问时, 该页面的访问计数器加1。在发生缺页中断时,淘汰计数值最小的那个 页面。
🌔 2、LRU与LFU的区别:
LRU 考虑的是最久未使用的,LFU 考虑的是使用频次最少的
🌔 3、存在的问题:
- 缺乏对时间的考虑,可能刚开始使用次数比较多,后期就没怎么用,在按照此算法置换时,可能就把这个页面保留在内存中。
- 可以通过定期将次数寄存器右移一位(使用次数除2)
七、Belady现象、LRU FIFO Clock 的比较
🌔 1、什么是Belady(人名)现象呢?
正常我们分配更多的页帧是为了减少出现缺页中断,但是在使用FIFO置换算法时,
有时会出现分配的物理页面数量增加,但是缺页率反而提高的异常现象。
🌔 2、为什么会出现 Belady 现象呢?
- 该算法的置换特征与进程访问内存的动态特征是矛盾的
- 与置换算法的目标是不一致的
- 原因:置换出去的进程并不一定是进程不会访问的
🌔 3、案例分析:
- 红色方框圈起来的部分最就有说明4
- 插入页面5,,移除页面1,但是接下来就需要调用页面1,所以还要将页面1重新导入
🌔 4、LRU、FIFO、Clock 的比较【最长时间未使用、先进先出、时钟页面】
- LRU算法性能较好,但是系统开销大,FIFO系统开销小,但是可能会发生Belady现象,Clock属于他们的折中
- LRU算法和FIFO算法都是先进先出的思路,第一个侧重页面的最近访问时间,后者侧重页面进入内存的时间,当进入的页面只调用了一次,那么LRU与FIFO近似
- 对于未被访问的页面,Clock和LRU算法的表现一样好。
- 对于被访问过的页面,Clock算法不能记录准确访问顺序,而LRU算法可以。
八、工作集算法
- 此种算法属于 全局置换算法
- 程序的访问不是固定不变的,而是处于一个动态变化的过程,所以使用局部变量都具有一定的局限性
🌔 1、工作集算法的实现原理:
- 通过一个固定的窗口来保存正在访问的页,替换不存在窗口中的页,窗口的大小是预先指定的
- 随着时间的发展,窗口处于一个不断平移的状态
- 当一个页面不在工作集窗口时,就要丢弃这个页面,而不是等到发生缺页中断的时候
🌔 2、工作集算法案例分析:
- 窗口大小为 4
- 为了方便查看,将页面的调用绘制成一条时间线
-
访存链表:维护窗口内的访存页面链表
-
访存时,换出不在工作集的页面;更新访存链表
-
缺页时,换入页面;更新访存链表
-
可以确保在物理内存中始终有足够多的页存在,这样可以给其它运行程序提供更多的内存,进一步减少页面置换的次数
九、缺页率置换算法
🌔 1、什么是缺页率置换算法?
与工作集算法类似也属于全局算法,不同点在于工作集的窗口大小是动态变化的,这样可以满足更多的程序调用,缺点在于会增加系统开销
🌔 2、那么这个动态变化得窗口是如何实现的呢?
- 当缺页率高的时候 >> 增加工作集
- 当缺页率低的时候 >> 减少工作集
🌔 3、什么是缺页率?
缺页次数 / 内存访问次数 或缺页的平均时间间隔的倒数
🌔 4、什么会影响缺页率的情况呢?
- 选择的页面置换算法
- 分配给今晨高的物理页面数目
- 页面的大小
- 程序的编写方法以及语言的选择
🌔 5、缺页率算法的实现?
一般都会设置一个标准时间 T,相邻两次发生缺页中断的时刻为 last 和 current
current - last > T 移除 last到current时间段内没有引用的页面
current - last <= T 将缺页添加到工作集中
- 动态调整常驻集,确保经常访问的能保留在内存中
🌔 6、案例分析:
- 时刻1、4时刻发生两次中断,大于预定窗口2,所以将这段时间未调用的页面淘汰,所以会舍弃a页面和e页面
- 以此类推
十、抖动问题
🌔 1、抖动问题指的是什么?
当常驻集 一直不超过 工作集,那么进程就会造成很多缺页中断,需要频繁的在内存和外存之间替换页面,从而使运行速度变得很慢,我们把这种状态称为抖动。
🌔 2、为什么会产生抖动?
随着驻留内存的进程数目增加,分配给每个进程的物理页面数不断就减小,缺页率不断上升。
🌔 3、那么我们如何缓解抖动问题呢?
- 从图中可以看出,当进程数过高和过低都不能充分的利用CPU
- 操作系统希望运行的程序尽量多,而且系统的利用率也比较高
- 所以0S要选择 一个适当的进程数目和进程需要的帧数,以便在并发水平和缺 页率之间达到一个平衡。