页面置换算法:

当出现缺页异常,需要调入新页面而内存已满时,需要使用置换算法选择被置换的物理页面。
局部、全局。
全局置换算法:不区分置换的这个页面到底属于哪个进程,这样的话就隐含着后边有每个进程分配的物理页面数会做调整。
局部页面置换算法:分配给一个物理进程的页面数已经确定了,选择范围仅限于当前进程占用的物理页面内。

  • 最优算法
  • 先进先出
  • 最近最久未使用
  • 时钟
  • 最不常用

全局页面置换算法:忽略进程的限制,置换页面的选择范围是所有可换出的物理页面。

  • 工作集算法
  • 缺页率算法

局部页面置换算法

最优页面置换算法:

  • 1 缺页时,计算内存中每个逻辑页面的下一次访问时间。
  • 2 选择未来最长时间不访问的页面。
  • 特征:缺页最少、最理想情况;实际系统中无法实现;无法预知每个页面在下次访问前的等待时间。
  • 作为其他置换算法的性能评价依据。
  • 在模拟器上运行某个程序,并记录每一次页面的访问情况
  • 第二遍运行时使用最优算法

    内存中共有四个页面,前四个均没有缺页,当访问e时出现缺页,那么就看后续的页面什么时候访问,a在7时刻b在6时刻c在9时刻d在10刻,所以将最远访问的d替换;继续访问,直到访问d页面时出现缺页,后续不再有页面,那么替换任何一个出去都可以,所以一共出现了两次缺页异常。所以这个算法是无法实现的,因为没有办法预知未来的页面访问情况,只可以作为评价其他算法的参考标准。

先进先出算法:选择在内存中驻留时间最长的页面进行置换。

  • 维护一个链表,记录所有位于内存中的逻辑页面
  • 链表元素按驻留内存的时间排序,链首最长,链尾最短
  • 当出现缺页时,选择链首页面进行置换,新页面添加到链尾
  • 实现简单;性能较差,调出的页面可能是经常访问的;进程分配物理页面数增加时,缺页并不一定减少。

最近最久未使用算法:选择最长时间没有被访问的页面进行置换。

  • 缺页时,计算内存中每个逻辑页面的上一次访问时间;
  • 选择上一次使用到当前时间最长的页面
  • 最优算法的一种近似。
  • 维护一个链表,按最近一次访问时间排序,记录页面
  • 链首节点是最近刚刚使用过的页面
  • 链尾节点是最久未使用的页面
  • 访问内存时,找到相应的页面并把它移到链首
  • 缺页时,置换链尾节点的页面
  • 第二种实现方法:
  • 访问页面时,将此页号压入栈,并将栈内相同的页号取出
  • 缺页时,置换栈底的页面
  • 特征:开销大
  • 当在5时刻访问e时出现缺页,此时计算内存中页面的访问时间。a在2时刻访问,b在4时刻访问,d在3时刻访问,c在1时刻访问,所以将c置换;继续访问,当在时刻9访问c时出现缺页,重新计算内存中页面的访问时间:a=7,b=8,c=5,d=3,所以将d置换;当在时刻10访问d时出现缺页,和上述一样,计算内存中每个页面的访问时间,选择最长未访问的页面置换。

时钟置换算法

  • 仅对页面的访问情况进行大致统计。它只是统计过去一段时间这个页面是否被访问过,访问过我留下,没访问过的我就按照进来的先后顺序,或者说它按照现有的顺序来做排序了。
  • 数据结构:
  • 在页表项中增加访问位,用于描述在过去一段时间内是否被访问过
  • 过去一段时间是依靠一个指针进行约定,
  • 指针将各页面组织成环形链表,指针在环形链表上进行周期性的循环
  • 指针指向最先调入的页面
  • 算法:
  • 访问页面时,在页表项记录页面的访问情况
  • 缺页时,从指针处开始顺序查找未被访问的页面进行置换
  • 算法实现:
  • 页面装入内存时,访问位初始化为0
  • 访问页面(读/写)时,访问位置置为1
  • 缺页时,从指针当前位置顺序检查环形链表
    - 访问位为0,置换该页面
    - 访问位为1,则更改访问位置为0(开始一次新的计时),并将指针移动到下一个页面,直到找到可置换的页面。

  • 指针开始位置在a处。当访问c时,将访问位置为1,a、b、d做相同操作;当访问e时出现缺页,此时从指针当前位置检查链表,a的访问位为1将其置为0,b置为0,c置为0,d置为0,重新扫描到a,因为访问位为0所以将其置换为e,并将e的访问位置为1,并且指针下移指到b处;当访问b时不缺页将访问位置为1,访问a时缺页,将b置为0,指针扫描到c的访问位为0将其置换成a,并设a的访问位为1,指针下移到d处;访问b时不缺页将访问位置为1,访问c时缺页,指针所指向的d访问位为0所以将其置换为c,并置c的访问位为1,指针下移到e处,访问d时出现缺页,逐个扫描,并将访问位为1的置为0,直到找到一个访问位为1的将其置换。

改进的时钟算法
我们考虑到的仅仅是它访问的情况,如果说你访问的那一页,是被修改过的,那么这时候呢它缺页中断的处理时间,就会是当前这个时间的至少是2倍,你需要把原来的内容写出去,再把新的内容读进来。在缺页中断这段时间太长,我们需要对它做改进
改进的时钟算法,基本思路是说对有修改的地方,如果你有修改,那我这时候跳过这一页我不做置换,在系统里它会定期的,把这些修改过的写到外存里头去。

  • 增加一个修改位,如果当前页面的修改位为1,则跳过不处理

  • c只读:访问位为1,修改位为0;a写入:访问位和修改位均置为1;d只读和c一样处理;b可写和a一样处理;访问e时出现缺页,指针的初始位置在a处,11的改为01,10的改成00,一遍扫描完成之后,01的改为00,(星号表示这部分修改的内容还没有写入到外存去),都为0的将其置换,所以将c置换,将e读入置为10,指针下移;访问b将b置为10,a置为11,c出现缺页,替换d换成c,d出现缺页,11改为01,10改为00,一遍之后a的01改为00,b为00将其置换。

最不常用算法

  • 置换访问次数最少的页面。
  • 每个页面设置一个访问计数;访问页面时,访问计数加1;缺页时,置换计数最小的页面。
  • 特征:算法开销大;
  • 就是一个页刚拿进来没访问几次,又把它置换出去,这是它存在的一个麻烦,它的问题是开销大。并且,计数值还没长的很大的时候,可能频繁的是这些页面,刚拿进来又拿出去。
  • 后续有一个改进就是对这个,已经计了数的这些值比较大的,它会定期做衰减右移,那这样的话它计数值会变小
  • 初始访问次数很大,后来不再访问了,但仍有可能不被置换。

Belady现象:随着分配给进程的物理页面的增加,缺页率会减少吗?

  • 我们给每一个进程分配一定数目的物理页面,如果说它缺页次数比较多,那麽会增加给它的页面数,增加完了之后,按照通常的理解,它的缺页应该降低,但实际上如果算法不好,比如说FIFO,在某些情况下 你增加页面之后,它的缺页次数反而会增加,这种现象就叫Belady。
  • 置换算法标记的特征和进程访问的特征不一致导致的。
  • LRU没有Belady现象。

LRU依据页面的最近访问时间排序
FIFO依据页面进入内存的时间排序
LRU需要动态的调整顺序所以开销大(栈内相同页面的顺序调整)
FIFO的页面进入时间是固定不变的不需要调整
LRU可退化成FIFO,如果页面进入内存后没有被访问,最近访问时间与进入内存时间相同,(只访问了一次)
时钟算法是他们的折中,仅记录访问过的

  • 页面访问时,不动态调整页面在链表的顺序,仅做标记
  • 缺页时,再把它移动到链表末尾

全局页面置换算法

局部置换算法没有考虑进程之间访问内存的差异性。

全局置换算法为进程分配可变数目的物理页面。随着进程在不同阶段对内存需求的变化而变化。

页面置换算法代码python 页面置换算法_页面置换算法代码python


工作集算法:

页面置换算法代码python 页面置换算法_链表_02


在不同时间段,进程访问页面的数目是不一样的,如果能够依据访问数目的大小分配相应的页面就能很好的满足进程的需求。

页面置换算法代码python 页面置换算法_页面置换算法代码python_03


常驻集:当前时刻进程实际驻留内存的页面的集合

页面置换算法代码python 页面置换算法_链表_04


工作集置换算法:

  • 换出不在工作集中的页面
  • 当前时刻前τ个内存访问的页引用是工作集,τ被称为窗口大小。
  • 实现方法:
  • 维护窗口内访存页面链表
  • 访存时,换出不在工作集的页面;更新访存链表(开销大)
  • 缺页时,换入页面;更新访存链表
  • 内存中的页面有e、d、a,t=1访问c时缺页,载入,此时内存中有e、d、a、c;t=2访问c时不缺页,但此时工作集中页面不再包括e(超出τ)只有dac;t=3时不缺页,工作集页面acd;t=4时b缺页载入,工作集页面cdb;t=5时不缺页工作集页面dbc;t=6时e缺页载入,工作集页面dbce;t=7时不缺页,工作集页面bce;t=8时不缺页工作集页面ce;t=9时a缺页,载入,工作集页面cea;t=10时d缺页,载入,工作集页面cead。

缺页率置换算法:缺页次数/内存访问次数或缺页平均时间间隔的倒数
影响缺页率的因素

  • 页面置换算法
  • 分配给进程的物理页面数目
  • 页面大小
  • 程序的编写方法

    通过调节常驻集的大小,使每个进程的缺页率保持在一个合理的范围内
  • 若进程的缺页率过高,则增加常驻集以分配更多的物理页面数
  • 若进程的缺页率过低,则减少常驻集以减少它的物理页面数

算法实现:

  • 访存时,设置引用位标志
  • 缺页时,计算上次缺页时间tlast到现在tcurrent的时间间隔
  • 如果tcurrent-tlast>T,则置换所有在[tlast,tcurrent]时间间隔内没有被引用的页;(相当于缺页率比较低,减少常驻集大小,把不用的页面置换出去)
  • 如果间隔<=T,则增加缺失页到常驻集中

    t=1时c缺页载入,常驻集页面adec;t=2时c不缺页,常驻集页面不变;t=3时d不缺页,常驻集页面不变;t=4时b缺页载入,并且缺页间隔4-1=3>2,此时需要将该间隔内没有被引用的页置换,所以此时常驻集页面为cdb;t=5时c不缺页,页面不变;t=6时e缺页,载入,缺页间隔6-4等于2,所以不置换,常驻集页面为cdbe;t=7时c不缺页,页面不变;t=8时不缺页,页面不变;t=9时a缺页,载入,间隔9-6=3>2,所以将db置换,常驻集页面变为cea;t=10时缺页间隔=1<2,所以不置换,常驻集页面为cead。
  • 工作集置换算法在应该淘汰哪一个页面时是在每次访问的时候,开销较大;
  • 缺页率置换算法是在当间隔足够大的时候进行页面淘汰

抖动

  • 进程数目太多,每个进程分配到的物理页面太少,不能包含工作集
  • 造成大量缺页,频繁置换;
  • 进程运行速度变慢

产生抖动的原因:

  • 随着驻留内存的进程数目增加,分配给每个进程的物理页面数不断减小,缺页率不断上升

OS需要在并发水平和缺页率之间达到一个平衡

  • 选择一个适当的进程数目和进程需要的物理页面数

负载控制:

  • 通过调节并发进程数来进行系统负载控制。
  • 工作集总和
  • 平均缺页间隔时间MTBF/缺页异常处理时间PFST
  • 如果MTBF>PFST,那么异常处理是来得及完成的