• 虚存技术(下)


    请求分页系统建立在基本分页系统基础之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。

    在请求分页系统中,只要求将当前需要的一部分页面装入内存,以便可以启动作业运行。在作业执行过程中,当所要访问的页面不在内存时,再通过雕爷功能将其调入,同时还可以通过置换功能将暂时不用的页面换出到外存上,以便腾出内存空间。

    页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。

    常见的页面置换算法有以下几种:

    1、最佳置换算法(Optimal,OPT)

    2、先进先出页面置换算法(First In First Out,FIFO)

    3、最近最久未使用( Least Recently Used,LRU)置换算法

    4、第二次机会算法

    5、时钟算法(clock)

    6、改进时钟算法

    7、最不常用算法(LFU,Least Frequently Used)

    1、最佳置换算法(Optimal,OPT)
    所选择的被换出的页面将是以后永不使用的,或者是在最长时间内不再被访问,通常可以保证获得最低的缺页率。但是由于人们无法预知一个页面多长时间不再被访问,因此该算法是一种理论上的算法。最佳置换算法可以用来评价其他算法。

    举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:

    开始运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,根据最佳置换算法,页面 7 在第18次访问才需要调入,再次被访问的时间最长,因此会将页面 7 换出,后面的过程以此类推,具体过程如下图;

     

    2、先进先出页面置换算法(First In First Out,FIFO)
    选择换出的页面是最先进入的页面。该算法实现简单,但会将那些经常被访问的页面也被换出,从而使缺页率升高。

    举例:仍使用上面的例子,使用FIFO算法进行页面置换,过程如下:

     

    进行了12次页面置换,比最佳置换算法正好多一倍。

    FIFO算法还会产生 当分配的物理块数增大而页故障数不减反增的异常现象,称为Belady异常。FIFO算法可能出现Belady异常,而LRU和OPT算法永远不会。

    3、最近最久未使用( Least Recently Used,LRU)置换算法
    虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出,它认为过去一段时间内未使用的页面,在最近的将来也不会被访问。

    实现方式一:

    在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面时最近最久未访问的。

    实现方式二:

    为每个页面设置一个访问字段,来记录页面自上次被访问以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。

    使用和上面同样的实例,采用LRU算法进行页面置换:

     

    LRU性能较好,但需要寄存器和栈的硬件支持,LRU是堆栈类的算法,理论上可以证明,堆栈类算法不可能出现Belady异常,FIFO算法基于队列实现,不是堆栈类算法。

    4、第二次机会算法
    FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改:

    当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。

    5、时钟算法(clock)
    第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面链接起来,再使用一个指针指向最老的页面。

    最简单的时钟策略需要给每一页框关联一个附加位,称为使用位。当某一页首次装入内存中时,则将该页页框的使用位设置为1;当该页随后被访问到时(在访问产生缺页中断之后),它的使用位也会被设置为1。该方法中,用于置换的候选页框集合(当前进程:局部范围;整个内存;全局范围)被看做是一个循环缓冲区,并且有一个指针针与之相关联。当一页被置换时,该指针针被设置成指向缓冲区中的下一页框。当需要置换一页时,操作系统扫描缓冲区,以查找使用位被置为0的一页框。每当遇到一个使用位为1的页框时,操作系统就将该位重新置为0;如果在这个过程开始时,缓冲区中所有页框的使用位均为0时,则选择遇到的第一个页框置换;如果所有页框的使用位均为1时,则指针针在缓冲区中完整地循环一周,把所有使用位都置为0,并且停留在最初的位置上,置换该页框中的页。当需要使用的页已经存在时,则指针不会受到影响,不会发生转动。

    可见该策略类似于FIFO(先进先出),唯一不同的是,在时钟策略中使用位为1的页框被跳过,该策略之所以称为时钟策略,是因为可以把页框形象地想象成在一个环中。许多操作系统都采用这种简单时钟策略的某种变体。

    以下是一个使用实例,其中*号表示相应的使用位为1,红色单元格表示指针指向的位置

    6、改进时钟算法
    在页面中增加了修改位,1为修改过,0为未修改过。因为当发生缺页中断时,把未修改过的页面替换进外存就相当于把页面直接从内存中删除,因为内存和外存中所对应的该页面的内容相同,处理时间只有一次缺页中断访问外存的时间。而修改过的页面则还需要向外存中写入一次,再加上缺页中断的时间,相当于访问了两次外存,是上述未修改的两倍。所以避免把修改过的页面替换下去可以提高性能。

    由访问位A和修改位M可以组合成下面四种类型的页面: 

    • 1类(A=0, M=0): 表示该页最近既未被访问, 又未被修改, 是最佳淘汰页。 
    • 2类(A=0, M=1): 表示该页最近未被访问, 但已被修改, 并不是很好的淘汰页。 
    • 3类(A=1, M=0): 最近已被访问, 但未被修改, 该页有可能再被访问。 
    • 4类(A=1, M=1): 最近已被访问且被修改, 该页可能再被访问。

    可能有人会发现第2类这种情况根本不会出现,如果一个页帧被修改,其修改位会被置1,同时它也被使用了,其使用位也会被置1;即不会出现被修改但是没有被使用的情况。真实情况是,页帧的使用位可能会被清零,这样第3组经过一次清零就会变成第2组。

    算法执行如下操作步骤:

    1.从指针的当前位置开始,扫描帧缓冲区。在这次扫描过程中,对使用位不做任何修改。选择遇到的第一类页(A=0,M=0)作为淘汰页。

    2.如果第1)步失败,则开始第二轮扫描,查找(A=0,M=1)的第二类页。选择遇到的第一个这样的页作为淘汰页。在这个扫描过程中,对所有经过的页,把它的访问位A设置成0。
    3.如果第2)步失败,指针将回到它的最初位置,并且集合中所有页的访问位均为0。重复第1步,并且如果有必要,重复第2步。这样将可以找到被淘汰的页。
    改进型的CLOCK算法优于简单CLOCK算法之处在于替换时首选没有变化的页。由于修改过的页在被替换之前必须写回,因而这样做会节省时间。

    7、最不常用算法(LFU,Least Frequently Used)
    是基于“如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小”的思路。

    这种算法选择最近时期使用次数最少的页作为淘汰页。为每个页面配置一个计数器,一旦某页被访问,则将其计数器的值加1,在需要选择一页置换时,则将选择其计数器值最小的页面,即内存中访问次数最少的页面进行淘汰。

    这种算法可能存在的问题是:有些也在进程开始时被访问的次数很多,但以后这些页可能不再被访问,这样的页不该长时间停留在内存中。解决这个问题的方法之一是定期的将计时器右移,以形成指数衰减的平均使用次数。

    注意LFU和LRU算法的不同之处,LRU的淘汰规则是基于访问时间,而LFU是基于访问次数的。

    抖动

    Belady现象(Bélády's anomaly)是指:当给一个进程增加页帧数分配时,在FIFO替换算法策略下可能会出现缺页率增加的异常现象。
    (In computer storage, Bélády's anomaly is the phenomenon in which increasing the number of page frames results in an increase in the number of page faults for certain memory access patterns. )

    Belady现象演示

    假定给某进程分为5页(page),但是它在内存中只分配到3个页帧(page frame),现在有一访问串:1,2,3,4,1,2,5,1,2,3,4,5,表示依次访问第1页、第2页……
    1. 刚开始时,进程页还在虚存(磁盘)中,尚未缓存到内存中,所以第一次要访问第1页时发生一次缺页故障,此时调入第1页到内存中,占一个页帧
       
       
    2. 此时还剩下两个页帧未分配,由于接下来依次访问第2、3页,同理会触发两次缺页故障,在此之后,第1、2、3页都已经缓存在内存中
       
       
    3. 接下来要访问第四页,由于在此之前第1,2,3页已经缓存在内存中,该进程所分配到的3个页帧已满,为此必须替换掉一页,才能把第四页加载进来,此时又发生一次缺页故障。由于采用FIFO替换算法,因为第一页是最先进来,所以它会被替换出去
       
       
    4. 接下来又要访问第一页,由于当前缓存页时第4、2、3页,从而根据FIFO,要将第2页替换为第1页,这就又发生一次缺页中断,调入第1页后,此时存在于内存中的是第4、1、3页。同理,接下来要访问第2页,发生一次缺页中断,将第3页替换为第2页,此时存在于内存中的是第4、1、2页。
    5. 在接下来的访问中,如果第K页已经存在内存中,则直接使用,所以此时不会发生缺页故障,重复按照上述过程,我们可以得到如下示例图表:
       
       
      红色标识出的是发生缺页故障后调入的页,可以看见共发生9次缺页异常,而从访问串可知访问12次,所以缺页率为9/12=0.75
    现在,该进程在上述3页帧的基础上多分配一页帧,也就是变成四页帧,则仿照上述分析过程,可画出如下图表
     
     
    红色标识出的是发生缺页故障后调入的页,蓝色标识的是之前调入的页面,可以看见共发生10次缺页异常,而从访问串可知访问12次,所以缺页率为10/12=0.833
    FIFO替换算法产生该现象的原因是它没有考虑到程序执行的动态特征。
  • 相关阅读:
    内存中的线程
    python高级线程、进程和进程池
    生产者以及消费者模式(进程池)
    生产者以及消费者模式(多进程)
    生产者以及消费者模式
    全局解释器锁(GIL)
    JoinableQueue队列实现消费之生产者模型
    什么是Sikuli?
    协程基础
    装饰器
  • 原文地址:https://www.cnblogs.com/cjsword/p/12169137.html
Copyright © 2020-2023  润新知