操作系统常见的十种页面置换算法

hfut-OS常见页面置换算法整理

一、定义:

在地址映射过程中,若在页面中发现所要访问的页面不在内存中,则产生缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。

二、目标:

如今已经有很多页面置换算法,但是不同页面置换算法的主要目标还是使页面置换频率最低(即缺页率最低)。

三、常见的算法:

1. 最佳置换算法

基本思想:选择以后再也不用的页面;没有的话,选择以后最长时间不用的页面;

实现:无法实现,因为页面的访问顺序无法预知;

特点:无法实现,仅具有理论意义;

2. 先进先出置换算法(FIFO)

基本思想:基于程序的顺序执行特点选择到达内存最早的页面,予以淘汰;

实现:页面在内存中按时间排序;

特点:效果不佳(程序不是严格顺序执行);

3. 最近最久未使用置换算法(LRU)

基本思想:基于程序运行的局部性原理,选择最近以来最久未使用的页面,予以淘汰;

实现:移位寄存器,栈;

特点:调度性能教好;

4. 第二次机会算法

第二次机会算法的基本思想是与FIFO相同的,但是有所改进,避免把经常使用的页面置换出去。当选择置换页面时,依然和FIFO一样,选择最早置入内存的页面。但是二次机会法还设置了一个访问状态位。所以还要检查页面的的访问位。如果是0,就淘汰这页;如果访问位是1,就给它第二次机会,并选择下一个FIFO页面。当一个页面得到第二次机会时,它的访问位就清为0,它的到达时间就置为当前时间。如果该页在此期间被访问过,则访问位置为1。这样给了第二次机会的页面将不被淘汰,直至所有其他页面被淘汰过(或者也给了第二次机会)。因此,如果一个页面经常使用,它的访问位总保持为1,它就从来不会被淘汰出去。

第二次机会算法可视为一个环形队列。用一个指针指示哪一页是下面要淘汰的。当需要一个存储块时,指针就前进,直至找到访问位是0的页。随着指针的前进,把访问位就清为0。在最坏的情况下,所有的访问位都是1,指针要通过整个队列一周,每个页都给第二次机会。这时就退化成FIFO算法了。

5. 时钟算法

需要用到页表项当中的访问位,当一个页面被装入内存时,把该位初始化为0,然后如果这个页面被访问(读/写),则把该位置为1;把各个页面组织成环形链表(类似于钟表面),把指针指向最老的页面(最先进来);当发生一个缺页中断时,考察指针所指向的最老页面,若它的访问位为0,立即淘汰;若访问位为1,则把该位置为0,然后指针往下移动一格,如此下去,直至找到被淘汰的页面,然后把指针移动到它的下一格。

6. 改进型的时钟置换算法

简单的时钟置换算法仅考虑到一个页面最近是否被访问过。事实上,如果被淘汰的页面没有被修改过,就不需要执行I/O操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。因此,除了考虑一个页面最近有没有被访问过之外,操作系统还应考虑页面有没有被修改过。在其他条件都相同时,应优先淘汰没有修改过的页面,避免I/O操作。这就是改进型的时钟置换算法的思想。

修改位=0,表示页面没有被修改过;修改位=1,表示页面被修改过。为方便讨论,用(访问位,修改位)的形式表示各页面状态。如(1,1)表示一个页面近期被访问过,且被修改过。算法规则:将所有可能被置换的页面排成一个循环队列。

操作系统常见的十种页面置换算法_第1张图片

 

实例:

第一轮:从当前位置开始扫描到第一个(0, 0)的帧用于替换。本轮扫描不修改任何标志位。

操作系统常见的十种页面置换算法_第2张图片

 

第二轮:若第一轮扫描失败,则重新扫描,查找第一个(0, 1)的帧用于替换。本轮将所有扫描过的帧访问位设为0。

操作系统常见的十种页面置换算法_第3张图片

 

第三轮:若第二轮扫描失败,则重新扫描,查找第一个(0, 0)的帧用于替换。本轮扫描不修改任何标志位。

操作系统常见的十种页面置换算法_第4张图片

 

第四轮:若第三轮扫描失败,则重新扫描,查找第一个(0, 1)的帧用于替换。

操作系统常见的十种页面置换算法_第5张图片

 

由于第二轮已将所有帧的访问位设为0,因此经过第三轮、第四轮扫描一定会有一个帧被选中,因此改进型CLOCK置换算法选择一个淘汰页面最多会进行四轮扫描。

操作系统常见的十种页面置换算法_第6张图片

 

7. 最近未使用页面置换算法(NRU)算法

找到最久没有使用的页面置换出去,页面被访问时设置访问位为1,修改时设置修改位为1,为便于说明,用R位标识访问位,M位标识修改位。R位定期清0;

此算法可以把页面分四类:

  • 未被访问,未被修改的R=M=0
  • 未被访问,被修改R=0,M=1
  • 被访问,未被修改R=1,M=0
  • 被访问,被修改R=1,M=1

置换方式:系统从类类编号最小的非空类随机挑选一个置换。

8. 最不常用算法

用一个软件模拟LRU,该算法将每个页面与一个软件计数器相关联。计数器的初值为0。每次时钟中断时,由操作系统扫描内存中所有的页面,将每个页面的R位(它是0或1)加到它的计数器上。这个计数器大体上跟踪了各个页面被访问的频繁程度。发生缺页中断时,则置换计数器值最小的页面。
    NFU的缺点是它不从不忘记任何事,比如一个页面之前频繁被访问,导致这个它的计数器很大,但是后来它不被访问了,而它的计数器的值还是很大,所以它一直不会被置换出去。

9. 老化算法

老化算法是对NFU算法的修改,其修改包括两个部分,首先,在R位被加进之前将计数器右移一位,其次,将R位加到计数器最左端的位而不是最右端的位。
    老化算法中的计数器只有有限位数,如果时钟滴答是20ms,8位一般是够用的。假如一个页面160ms没有被访问过,那么它很可能并不重要。

10. 工作集页面置换算法

相关定义:

  1. 一个进程当前正在使用的页面的集合称为它的工作集。
  2. 若每执行几条指令就产生一次缺页中断,那么就称这个程序发生了颠簸。
  3. 在单纯的分页系统中,刚启动进程时,在内存中并没有页面。在CPU试图读取第一条指令时就会产生一次缺页中断,使操作系统装入含有第一条指令的页面,其他由访问全局数据和堆栈引起的缺页中断通常会紧接着发生。一段时间后,进程需要的大部分页面都已经在内存了,进程开始在较少缺页中断的情况下运行。这个策略被称为请求调页。
    有不少分页系统会设法跟踪进程的工作集,以确保在让进程运行以前,它的工作集就已经在内存中了。该方法称为工作集模型,大大减少缺页中断率。在进程前装入其工作集页面也称为预先调页。工作集是随时间变化的。
  4. 事实上大多数程序会任意访问一小部分页面,工作集随时间缓慢变化。当程序重新开始时,就有可能根据它上次结束时的工作集对要用到的页面做一个合理的推测,预先调页就是在程序IXUS运行之前预先装入推测的工作集的页面。
  5. 按照以前的方法,定义工作集为前1000万次内存访问锁使用过的页面的集合,那么现在就可以这样定义:工作集即是过去10ms中的内存访问所用到的页面的集合。这样的模型很合适而且更容易实现。要注意到,每个进程只计算它自己的执行时间。因此,如果一个进程在T时刻开始,在(T+100ms)的时刻使用了40msCPU时间,对工作集而言,它的时间就是40ms。一个程序从它开始执行到当前所实际使用的CPU时间总数通常称作当前实际运行时间。通过这个近似的方法,进程的工作集可以被称为在过去的τ秒实际运行时间中它所访问过的页面的集合。
  6. 基于工作集的页面置换算法就是找出一个不在工作集中的页面并淘汰它。每个表项至少包含两条信息:上次使用该页面的近似时间和R(访问位)。

算法过程:

过程:扫描所有的页面检查R位:

若(R == 1)则设置上次使用时间为当前实际时间,表示缺页中断时该页面正在被使用。

若(R == 0 且生存时间>τ)则移出这个页面,该页面在当前时钟滴答中未被访问,不在工作集中,用新的页面置换它。扫描会继续进行以更新剩余的表项。

若(R == 0 且生存时间≤τ)则记住最小时间。如果该页面R==0且生存时间小于或等于τ,则页面仍在工作集中。把页面临时保存下来,但是要记住生存时间最长(“上次使用时间”的最小值)。如果扫描完整个页表却没有找到合适的淘汰的页面,如果找到了一个或多个R == 0的页面,就淘汰生存时间最长的页面。

     在最坏的情况下,在当前时钟滴答中,所有的页面都被访问过了,也就是所有的R都为1,因此就随机选择一个页面淘汰,如果有的话最好选一个干净页面。

工作集时钟页面置换算法

工作集时钟页面置换算法是在工作集和时钟算法的基础上改进的。

在工作集页面置换算法中中,当缺页中断发生后,需要扫描整个页表才能确定被淘汰的页面,因此基本工作集算法是比较费时的。
    基于时钟算法,并且使用了工作集信息,被称为WSClock(工作集时钟)算法。由于它实现简单,性能较好,所以在实际工作中得到了广泛应用。与时钟算法一样,所需的数据结构是一个以页框为元素的循环表。

操作系统常见的十种页面置换算法_第7张图片

 

最初,该表为空,当装入第一个页面后,把它加到该表中。随着更多的页面加入,它们形成一个环。每个表项包含来自基本工作集算法的上次使用时间,以及R位和M位。
    与时钟算法一样,每次缺页中断时,首先检查指针指向的页面。如果R位是1,该页面在当前时钟滴答中就被使用过,那么该页面就不适合被淘汰。然后把该页面的R位置为0,指针指向下一个页面,并重复该算法。
    如果R位是0,查看生存时间,如果生存时间大于τ并且该页面是干净的,它就不在工作集中,而且在磁盘上它有一个有效的副本。申请此页框,并把新页面放在其中。如果该页面已经被修改过,就不立即申请此页框,为了避免由于调度写磁盘操作引起的进程切换,指针继续向前走,算法继续对下一个页面进行操作,有可能存在一个旧的而且干净的页面可以立即使用。
    原则上,所有的页面都有可能因为磁盘I/O在某个时钟周期被调度,为了降低磁盘阻塞,需要设置一个限制,即最大只允许写回n个页面。一旦达到该限制,就不允许调度新的写操作。
指针经过一圈返回它的起点,有两种情况:

  1. 至少调用了一次写操作
  2. 没有调用过写操作
        对于第一种情况,执行了写操作的页面已经是干净的了,置换遇到的第一个干净页面,这个页面不一定是第一个被调度写操作的页面,因为硬盘驱动程序为了优化性能可能已经把写操作重排序了。
        对于第二种情况,所有的页面都在工作集中,否则将至少执行了一个写操作。由于缺乏额外的信息,一个简单的方法就是随便置换一个干净的页面来使用,扫描中需要记录干净页面的位置。如果不存在干净页面,就选定当前页面并把它协会磁盘。

算法对比:

算法

优缺点

最优算法

不可实现,但可以用作基准

NRU(最近未使用)算法

和LRU算法很相似

FIFO(先进先出)算法

有可能会抛弃重要的页面

第二次机会算法

比FIFO 有较大的改善

时钟算法

实际使用

LRU(最近最少)算法

比较优秀,但是很难实现

NFU(最不经常使用)算法

和LRU很类似

老化算法

近似LRU的高效算法

工作集算法

实施起来开销很大

工作集时钟算法

比较有效的算法

补充:

在 UNIX 系统中采用的页面置换算法是时钟CLOCK算法,

Windows NT的页面置换算法采用先进先出(FIFO)算法。

你可能感兴趣的:(算法,java,数据结构)