FIFO
FIFO先进先出页面置换算法:置换出当前已经待在内存里时间最长的那个页。
FIFO算法实现
通过维护一个链表结构去存储当前调入的页面;将最先进入的页面维护在链表的最前,最后进入的页面维护在链表的最后;这样,当发生缺页中断时,需要进行置换的时候,淘汰表头的页面并将新调入的页面加到链表的尾部;除了链表以外还可以采用数组或者队列等来进行实现。
FIFO算法特点
- FIFO算法实现简单,易于理解易于编程
- FIFO算法可能会出现Belady现象。也就是在FIFO算法中,如果未分配够一个进程所要求的页面,有时就会出现分配的页面数增多,缺页率反而增加Belady现象
- FIFO算法可能会置换调重要的页面,其效率不高
- 在FIFO算法可能中会导致多次的页面置换。当页面置换的时间大于所要操作的时间的时候,这时候其效率就会很低。当其不停的进行页面置换的时候会出现大量的系统抖动现象
LRU
1、简述LRU算法
LRU(最近最久未被使用)置换算法。在进行页面置换的时候,查找到当前最近最久未被使用的那个页面,将其剔除在内存中,并将新来的页面加载进来。
2、LRU算法的实现
可以采用哈希映射和链表相结合的方式实现。
方法一:数组
用一个数组来存储数据,给每一个数据项标记一个访问时间戳,每次插入新数据项的时候,先把数组中存在的数据项的时间戳自增,并将新数据项的时间戳置为0并插入到数组中。每次访问数组中的数据项的时候,将被访问的数据项的时间戳置为0。当数组空间已满时,将时间戳最大的数据项淘汰。数组:查询比较快,但是对于增删需要移动大量元素。
方法二:链表
利用一个链表来实现,每次新插入数据的时候将新数据插到链表的头部;每次缓存命中(即数据被访问),则将数据移到链表头部;那么当链表满的时候,就将链表尾部的数据丢弃。链表:查询比较慢,但是对于增删来说十分方便O(1)时间复杂度内搞定。
方法三:hash+链表
保证了查询和增删的时间复杂度O(1)。链表中包含key、value以及prev和pnext前驱和后继域。Hashmap用来作为一个检索表,它get过程的时间复杂度为O(1),那么通过双向链表进行set的过程时间复杂度也可到O(1)。
可以通过哈希映射快速检索到来的页面是否已经存在,如果已经存在的活,直接映射到链表中,将链表中该节点从当前位置移除直接插入到链表的头部,这样就能保证链表的尾部是最近最久未被使用的页面;头部是最近刚使用过的页面。
Get获取元素,通过HashMap可以直接映射到链表中,查看是否有命中的元素,如果有,将元素从当前位置删除,并且再将其插入到首位置;如果没有,返回NULL。
Set插入元素,插入前先通过HashMap查看该元素是否存在,如果存在则先从该位置移除,再将其插入到链表首部;如果不存在即没有命中,将元素插入到链表的首部,同时判断容量是否达到最大,如果达到最大,将链表尾部元素进行删除;HashMap同样也要进行更新删除。
3、LRU算法的特点
如果进程被调度,该进程需要使用的外存页(数据)不存在于数据块中,这个现象就叫做缺页。如果这个数据此时不在,就会将这个数据重新加入到数据块首部。
数据块插入与剔除:每次有新数据到来时,会将其放入数据块首部,当数据每次被访问时,会将其放入数据块首部;如果数据块满了,每次新进的数据都会将数据块尾部的数据挤出数据块。
LFU
1、LFU算法简述
LFU(最近最少未被使用)页面置换算法,当页面满时,需要进行页面置换的时候,所采取的措施是在缓存队列中找到最近使用次数最少的页面,将其剔除出去。将新的页面加载到页面缓存队列中。即在LFU中,需要记录每个页面被访问的次数。
2、LFU的实现方式
方法一:HashMap+数组
HashMap(存储数据项在数组中的对应关系)+数组(存储数据项+对应的引用计数)。为了能够淘汰最少使用的数据,因此利用一个数组存储数据项,用HashMap存储每个数据项在数组中对应的位置,然后为每个数据项设计一个访问频次,当数据项被命中时,访问频次自增,在淘汰的时候淘汰访问频次最少的数据。在插入数据和访问数据的时候都能达到O(1)的时间复杂度,在淘汰数据的时候,通过选择算法得到应该淘汰的数据项在数组中的索引,并将该索引位置的内容替换为新来的数据内容即可,淘汰数据的操作时间复杂度为O(N)。
方法二:HashMap+小顶堆
小顶堆是利用页面的访问次数进行构建;每次最少的访问次数的页面在小顶堆的堆根;利用HashMap进行映射,插入和删除操作的时间复杂度都是O(logN)。
Clock算法(时钟轮转法)
Second Chance算法
为了避免FIFO算法将重要的页换出内存,Second Chance算法在将页面换出内存前检查其使用位,如果其使用位为1,证明此页最近有被使用,猜测它还可能被使用,于是不把它置换出内存,但是把其使用位置为0,随后检查下一个页面,直到发现某页的使用位为0,将此页置换出内存。
为了节约Second Chance算法一个接着一个检查使用位的开销,时钟轮转法将所有的页组成一个圆,圆心的指针指向下一个要被置换的页面,置换前同样检查使用位,如果使用位为1,同样将其使用位置为0,随后将顺指针旋转,检查下一个页面,直到发现某页的使用位为0,将此页置换出内存。如图所示:
此时2号页是下一个要被置换出内存的页,置换时如果发现其使用位为1,则将使用位置0后顺时针旋转指针检查1号页。
补充:
缺页中断
在请求分页系统中,可以通过查询页表中的状态位来确定所要访问的页面是否存在于内存中。每当所要访问的页面不在内存时,会产生一次缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页,将其调入内存。
缺页本身是一种中断,与一般的中断一样,需要经过4个处理步骤:
1. 保护CPU现场
2. 分析中断原因
3. 转入缺页中断处理程序进行处理
4. 恢复CPU现场,继续执行
但是缺页中断时由于所要访问的页面不存在与内存时,有硬件所产生的一种特殊的中断,因此,与一般的中断存在区别:
1. 在指令执行期间产生和处理缺页中断信号
2. 一条指令在执行期间,可能产生多次缺页中断
3. 缺页中断返回时,执行产生中断的那一条指令,而一般的中断返回时,执行下一条指令