一、局部:时钟置换算法:
1.最优置换算法:理论上的,预测最晚调用的页面。
2.LRU算法,置换掉最久未使用的。
一个链表。一个页面被调用的话,会被从链表中(它原本的位置)移动到链表首,而每次缺页,则会将链表尾部元素置换。
3.FIFO算法,置换掉在内存中时间最长的。(性能低
同是一个链表,每次缺页置换最早进入页面(时间排序)链首的。新页面放在链表尾部。
4.clock 算法,
环形链表,不再排序而是使用2个标记,0和1,
第一个次加载页面的时候,页面标记被设置为0,调用内存中驻留的页面时,标记该页面为1,
出现缺页时,指针从当前位置循环查找环形链表,如果遇到标记为1的,标记为0,如果遇到标记为0的,置换它。
5.最不常用算法
标记不再是0和1,每次调用,标记值+1,缺页时,置换标记值最小的页面
优化版本:定期减小数字
clock 算法 虽然不能像LRU(least recently used)算法 一样精确的记录访问顺序,但是,开销较小。
改进版的clock 算法,只在访问同一个页面的时候,做写回操作,在缺页的时候,会跳过已经被改变的。
下面是一个小练习
function clock(load){ //假设同时可以加载的数目 let workRow =3; //储存标记位 let m = new Map(); //当前加载的 let res=[]; //当前加载的index,workRow个 let pointer = 0; //初始化 for(var i=0;i<load.length;i++){ if( res.length<workRow && !m.has(load[i]) ){ //如果没满,初始化 res.push(load[i]) //设置为1 m.set(load[i],0); //如果满了,而且需要加载的就在里面(重复)不用再加载 }else if(m.has(load[i])){ console.log('loaded what has been there',load[i]) m.set(load[i],1) }else{ //缺页异常,需要置换 loading(load[i],i) console.log(load[i] , res) } } function loading(task,idx){ let wait = true; //检查当前指针,如果是1,标记为0,如果找到为0的,扔掉,其余移动向下,把要加载的,加载进来,设置为1,结束 while(wait){ pointer = idx%(workRow-1) if(m.get(res[pointer])==1){ m.set(res[pointer],0) }else if(m.get(res[pointer])==0){ m.delete(res[pointer]) res[pointer]=task m.set(task,1) wait = false; } pointer++; } } //内存中最后的内容 return res; } clock(['a','b','b','d','b','e','c','d','e'])
二、全局:置换算法
1.尽量不更改常驻集大小的(假设工作集大小趋于稳定),工作集置换算法。
每次访存时,换出当前工作集窗口内没引用的页面。
每次缺页时,增加页面,更新访存链表。
2。动态改变常驻集(页面数)大小的,缺页率算法。
缺页率太大,增加常驻集,缺页率太小,减少常驻集。
而检测方法,是设置一个缺页之间的T间隔数,如果在这个T间隔范围内,没有出现缺页,(两次缺页之间的实际间隔t大于设定值T)则减小常驻集(置换所有未被引用的页面)。如果在这个范围内出现缺页,则增加常驻集大小(直接加入该页面到常驻集)。