本篇主要讲述页面置换的相关算法总结。
在地址映射过程中,若在页面中发现所要访问的页面不在内存中,则产生缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。
9.1 页面置换算法
9.1.1 FIFO页置换
FIFO页置换就是记录每一个页的时间,假如存在空闲页,追替换,否者替换最旧的页。
存在Belady异常,也即当k个页做置换的误差要比h个页做置换还要打,其中k>h
9.1.2 最优置换
Belady异常发现结果之一就是设计最优页面置换算法,该算法是所有页面置换算法中错误率最低的,并且不存在Belady异常。
最优页面置换算法是这样设计的:需要替换页的时候寻找最晚出现的页面,并选择替换掉,这个理论上错误率是最低的,但是需要了解未来的需要置换的页的序列,这个就很难做到了,只能做一个预测
9.1.3 LRU 页置换 Least Recently Used
最优置换是向后看,那么过采用向前看,也即讲过去最近使用作为将来的近视,这个技术LRU算法
如何实现LRU算法呢?有两种方法
1)计数器。给每一个页关联一个时间域,每次页引用计数器加一,置换具有最小时间的页即可
2)栈。每当引用一个页,从栈中删除改页并放到顶部,那么栈的顶部就是最近使用的页,需要置换的页在栈的底部,这个可以通过双向链表实现。
最优置换和LRU置换都没有Belady异常,因为他们是同一类算法,都是栈算法,这个是可以证明的,这里就不在描述了。需要注意的地方时如果自语TLB寄存器而没有其他的硬件支持,这两种LRU算法的实现都是不可能的。因为每次引用都要更新时钟或者栈,如果每次引用都采用中断允许软件去做相关修改,那么它会使内存引用过至少慢10倍,用户进程也至少慢10倍,没有系统可以容忍这么大的开销。
9.1.4 近视LRU页置换
因为很少有系统能够提供足够的硬件对LRU算法的支持,所以很多系统必须使用FIFO页置换算法。然而很多系统可以通过引用位提供一定的支持。页表每一项都有一个引用位,每当引用(无论是读还是写)页的时候引用位都会被硬件置位。
开始的时候引用位置位0,随着每一次的页引用,都会被置位1,通过检查引用位可以判断哪些被引用过哪些未被引用过,虽然不知道具体引用次序,但是这些信息也足够作为页面置换算法的基础。
因此右下面两个算法
附加引用位算法
可以为位于内存中的每个表中的页保留一个8bit的字节。操作系统把每个页的引用位转移到其8bit字节的高位,而将其他位右移,并抛弃最低位。如果将8bit字节作为无符号整数,那么具有最小值的页为LRU页,且可以被置换。二次机会算法
二次机会置换的基本算法是FIFO置换算法。当要选择一个页时,检查其引用位。如果其值为0,那么就直接置换该页。如果引用位为1,那么就给该页第二次机会,同时置换为0,并选择下一个FIFO页。当一个页获得第二次机会时,其引用位清零。且其到达时间设为当前时间。因此获得第二次机会的页,在所有其他页置换之前,是不会被置换的。另外,如果一个页经常使用以致于其引用位总是得到设置,那么它就不会被置换。
一种实现二次机会算法的方法是采用循环队列。用一个指针表示下次要置换哪个页。当需要一个帧时,指针向前移动直到找到一个引用位为0的页。在向前移动时,它将清除引用位。
- 增强型二次机会算法
通过将引用位和修改位作为一个有序对来考虑,能增强二次机会算法。有下面四种可能类型:
- (0,0)最近没有使用且也没有修改。—用于置换的最佳页;
- (0,1)最近没有使用但修改过。—不是很好,因为在置换之前需要将页写出到磁盘
- (1,0)最近使用过但没有修改—它有可能很快又要被使用;
- (1,1)最近使用过且修改过—它有可能很快又要被使用,且置换之前需要将页写出到磁盘
9.1.5 基于计数的页置换
有如下两种算法:
1. 最不经常使用页置换算法(LFU)
这个方法就是统计所有的引用页的次数,做一个计数,选择计数最小的去做置换。但是可能出现一个页用过的次数很多,但是以后不会用了,这个可以固定周期衰减计数器即可,比如固定周期右移一位。
- 最常使用页置换算法(MFU)
这个是基于这样的想方法:具有最小次数的页可能刚刚调进去,还没来得及使用,
这两种算法的实现都很费时,且不能很好地近似OPT置换算法。
9.1.6 页缓冲算法
系统通常保留一个空闲帧缓冲池。当出现页错误时,会像以前一样选择一个牺牲帧,在牺牲帧写出之前,所需要的页就从缓冲池中读到空闲内存。
9.1.7 全局分配和局部分配
全局置换允许进程从所有帧集合中选择一个进行置换,而不管该帧是否已分配给其他进程,即它可以从其他进程抢夺帧,比如高优先级抢夺低优先级的帧;局部分配则要求每个进程只能从自己的分配帧中分配。
全局置换通常有更好的吞吐量,且更为常用