一、局部:时钟置换算法:
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)则减小常驻集(置换所有未被引用的页面)。如果在这个范围内出现缺页,则增加常驻集大小(直接加入该页面到常驻集)。