一、局部:時鍾置換算法:
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)則減小常駐集(置換所有未被引用的頁面)。如果在這個范圍內出現缺頁,則增加常駐集大小(直接加入該頁面到常駐集)。