页面置换算法
在分页系统下,一个程序的所有页面并不一定都在内存中,那么如果当前需要使用的页面不在内存中,那么系统就会产生所谓的缺页中断,缺页中断程序负责将位于磁盘上的数据加载到物理内存来,如果物理内存中有空闲的页面就直接使用,如果没有就需要挑选一个页面进行替换,那么挑选那个页面才合适呢?
页面更换的目标
如果我们挑选用来替换的页面很快又要被访问,那么系统将再次发生缺页中断,缺页中断的代价是很大的,而且可能会出现系统抖动问题。
因此我们的目标就是降低随后发生的缺页中断的次数或者概率,因此我们选择的页面最好是随后很久不会被访问或者是再也不会被访问,同时我们希望替换的页面是一个没有被修改过的页面,因为被修改过的页面在置换时,是需要将修改的数据回写到磁盘上的
因此所有的页面置换算法被分为两大类:公平算法和非公平算法。对于公平算法即是所有的也页面被置换的可能性都是一样的,而非公平算法就是页面被置换的可能性不相同,因此就需要为每个页面维护更多的信息,供算法决策。
公平算法
- 随机算法
- 先来先出(FIFO)算法
- 第二次机会算法
- 时钟算法
非公平算法
- 最优算法
- NRU算法
- LRU算法
- 工作集算法
随机算法
最简单的就是随机算法,在需要进行页面替换是时,产生一个随机的页面号,然后将该页面号对应的物理页面替换掉。但是有研究表明。这种算法很很难满足被替换的页面随后很久都不会被访问,这种算法保很难证随后的缺页中断次数最小。
先进先出(FIFO)算法
FIFO算法就是使用链表将所有在内存中的页面按照进入时间的早晚连接起来,然后每次置换链表头上的页面即可,新增的页面就直接挂在链表末尾。FIFO实现非常简单,但是依然无法保证我们想要实现的目标。
第二次机会算法
第二次机会算法是对FIFO算法的一次提升,因为FIFO算法只关心页面进入内存的时间,但是不考虑页面被访问的频率,第二次机会就是为每个页面维护一个访问标记位,在进行页面替换时,检查标记位,如果没有访问,就直接替换,如果被访问,就将标记位清零,然后挂在到链表末尾。即相等于给了页面第二次机会。
第二次机会算法虽然简单,公平且易实现,但是每次将链表头部页面连接到尾部都需要消耗时间,并且页面只有在置换时才会将访问位清零,因此其时间局部性体现的不好,时间上的分辨力度太粗,影响页面替换的效率。
时钟算法
时钟算法是对第二次机会算法的提升,在时钟算法中,把页面排成一个时钟的形状,然后有一个针臂,每次进行更换页面时,从针臂的位置开始检查,如果当前页面的访问位为0,即上次检查到这次时间段,这个页面没有被访问过,就将该页面替换,如果被访问过就将访问位清零,并顺时针移动寻找没有被访问过的。
最优更换算法
毫无疑问,一个程序里的不同页面对程序的影响肯定是不同的,有的页面被频繁访问,但是有的页面被访问的次数较少。 那么最理想的页面替换算法就是选择一个再也不会被访问的页面进行替换,如果不存在,至少选择一个在随后最长时间都不会被访问的页面进行替换,从而保证随后发生的缺页中断的次数最小。这就是最优更换算法,但是这种算法是无法实际实现的短发,因此作为一个标杆,来判断其他算法的优劣。
最近未使用算法(NRU)
为每个页面维护一个修改位和访问位,然后在进行页面置换时,通过修改位和访问位的组合来选择一个页面进行置换,就是最近未使用算法。
最近未使用算法实现的机制是通过时空局域性原理,即最近未被访问的页面在很久一段时间都可能不会被访问,利用的就是修改位和访问位。
针对页面的修改位和访问位,凡是对页面进行读写操作时,访问位设置位1,而对页面进行写操作时,修改位设置为1,那么页面可以被分为四种类型。
页面类型 | 访问位 | 修改位 |
---|---|---|
第一种 00 | 未被访问 | 未被修改 |
第二种 01 | 未被访问 | 被修改 |
第三种 10 | 被访问 | 未被修改 |
第四种 11 | 被访问 | 被修改 |
第二种页面类型是可能存在的,因此系统会定期对访问位清零,如果不定期对访问为清零,一段时间后可能所有的页面的访问为都是1,那就没有意义了。但是修改位是不能能清零的,因为在页面置换时,回写磁盘也会使用到。
因此在考虑一个页面被访问的状态是有一个时间概念的,即在一段时间内被访问的情况。因为只有这样才能体现出所谓的时空局部性。
那么NRU算法有没有实现我们的目标呢,一和二是未被访的,三和四是被访问的,因此在一段时间内,三和四更容易被程序再次访问呢,因此优先替换一和二,在一和二中,二是被修改的,因此优先替换一,在三和四中,都是被访问的,但是三没有被修改,因此优先替换三。从而看来NRU算法确实实现了我们的目标。
但是当某一类页面有多个时,我们依然无法辨认应该替换那个更合适一些。
最近使用最少算法(LRU)
对NRU算法的改进就是NRU算法,因为我们不仅要看最近是否使用过,还需要看最近使用的频率。如果一个页面被访问的频率低,那么很可能以后都不会在使用。
那么LRU算法必须使用某种方式记录每个页面被访问的次数,最简单就是页面的记录项中添加一个计数域,在页面替换时选取计数器值最小的进行替换,但是计数器的长度有限,且计数器最小的不一定时最近的。
那么LRU同样使用一段时间来作为最近,然后在进行选择最少,所以LRU算法也采取定期清零的操作来实现。从而达到最近最少使用的情况。但是需要占用额外的空间,且定期清零也是需要开销的。
LRU算法的另一种简单实现方式就是使用一个链表将所有的页面连接起来,最近被使用总是在链表头部,最近未使用的放在链表末尾,在每次访问都对链表进行更新,确保最近被使用的总是在链表头部。但是这种方式的效率比较低,每次更新链表都有消耗。
此外LRU算法还有矩阵实现和为位移寄存器实现,这里不过多陈述。
工作集算法
工作集概念来源于程序访问的时空局部性,即在一段时间内,程序访问的页面局限在一组页面集上,例如:最近 k 次访问均发生在某m个页面上,那么m就是参数为k时的工作集,用W(k,t)表示在时间 t 时k次访问所涉及的页面数量。如下图
显然随着k增加,W的值也增加,但是当k到达某个值后,W就缓慢增加甚至停滞,并且维持一段时间的稳定。
由此可以看出,当一个程序在内存中的页面数与其工作集大小相等或者超过工作集,则程序在一段时间内不会发生缺页中断,否则会发生缺页中断的频率将增加。
因此工作集算法就是维护工作集中的页面,然后置换非工作集中的页面,因此程序内存中的页面被分为工作集内页面和工作集外页面。
工作集算法的实现
为每个页面增加一项信息来记录该页面最后一次被访问的时间,这个时间是一个按规律递增的一个虚拟时间,同时设置医一个时间值为T(也就是所谓的一段时间内),然后如果一个页面最后一次访问在当前时间减去T之前,即在T时间内,这个页面并没有再次被访问,则视为工作集外页面。否则视为工作集内页面。
那么在每次进行页面替换时,扫描所有的页面记录,进行如下操作:
- 如果访问位为1,将该页面的 最后一次访问时间设置为当前时间,然后将访问为清零。
- 如果访问位为0,检查其访问时间是否在当前时间减去T之前。
- 如果在,该页面是工作集外页面,直接替换。
- 如果不在,记录当前所有被扫描过页面的最后访问时间里的最小值。
那么如果有工作集外页面就替换掉,如果没有工作集外页面,在做替换时,就是替换最后访问时间里的最小值。因此他是工作集中最早被访问的页面。
页面置换策略
在也页面置换策略中,算法的应用对象可以分为全局和局部两类,即全局策略和局部策略。
全局策略
全局策略对应的是物理内存中的所有页面,即我们从所有的页面中选择需要替换的页面进行替换,即当前进程缺页中断,可能替换的另一个进程的页面,因此这种策略影响进程的内存使用。
全局策略的优点是系统的缺页率低,但是程序运行不稳定。因为程序无法控制自己的页面走向。
局部策略
算法对用的当前程序的所有页面,因此不会影响其他程序。
局部策略的优点是更加公平,程序更加稳定,但是缺点是不能充分利用系统的整体资源,可能造成不同程序之间在页面使用上不均衡。即有的程序页面富裕,但是有的页面却频繁缺页。
固定与可变驻留集
使用那种页面置换策略决定了一个进程在内存中所占页面的数量是否固定,局部策略选择本进程的页面进行替换,一个进程的物理页面将保持不变,即进程驻留内存的页面是固定的;全局策略由于动态的改变一个进程的物理页面数,即进程的驻留页面是可变的。因此支持固定页面驻留内存的使用局部策略,支持可变页面驻留内存的使用全局策略。
初始页面数确定
为每个进程分配内存块的算法有四种:均分法、比例法、优先权法和请求分页。
均分法
平均分配物理页面数,有新的进程加入,就需要重新分配
比例法
分配给进程的页面 = (进程地址空间大小 / 全部进程的总地址空间) * 可用页面数。同一样有新的进程时,也需要重新分分配。
优先权法
将进程的优先级考虑进来,加速优先级高的程序的执行。
请求分页法
一个进程在初始化时不分配页面,在需要的时候才一个页面一个页面的增加,当进程的缺页率下降到一定程度时,页面数量不在增加。
面试被问道,做一个简单的整理,有错误请指出,谢谢!!