下面原理來源:http://c.biancheng.net/cpp/html/2614.html
地址映射過程中,若在頁面中發現所要訪問的頁面不在內存中,則產生缺頁中斷。當發生缺頁中斷時,如果操作系統內存中沒有空閑頁面,則操作系統必須在內存選擇一個頁面將其移出內存,以便為即將調入的頁面讓出空間。而用來選擇淘汰哪一頁的規則叫做頁面置換算法。
1.最佳置換算法(OPT)(理想置換算法):從主存中移出永遠不再需要的頁面;如無這樣的頁面存在,則選擇最長時間不需要訪問的頁面。於所選擇的被淘汰頁面將是以后永不使用的,或者是在最長時間內不再被訪問的頁面,這樣可以保證獲得最低的缺頁率。
最佳置換算法可以用來評價其他算法。假定系統為某進程分配了三個物理塊,並考慮有以下頁面號引用串:
7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1
進程運行時,先將7, 0, 1三個頁面依次裝入內存。進程要訪問頁面2時,產生缺頁中斷,根據最佳置換算法,選擇第18次訪問才需調入的頁面7予以淘汰。然后,訪問頁面0時,因為已在內存中所以不必產生缺頁中斷。訪問頁面3時又會根據最佳置換算法將頁面1淘汰……依此類推,如圖3-26所示。從圖中可以看出釆用最佳置換算法時的情況。
可以看到,發生缺頁中斷的次數為9,頁面置換的次數為6。
訪問頁面 | 7 | 0 | 1 | 2 | 0 | 3 | 0 | 4 | 2 | 3 | 0 | 3 | 2 | 1 | 2 | 0 | 1 | 7 | 0 | 1 |
物理塊1 | 7 | 7 | 7 | 2 | 2 | 2 | 2 | 2 | 7 | |||||||||||
物理塊2 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | ||||||||||||
物理塊3 | 1 | 1 | 3 | 3 | 3 | 1 | 1 | |||||||||||||
缺頁否 | √ | √ | √ | √ | √ | √ | √ | √ |
2.先進先出置換算法(FIFO):是最簡單的頁面置換算法。這種算法的基本思想是:當需要淘汰一個頁面時,總是選擇駐留主存時間最長的頁面進行淘汰,即先進入主存的頁面先淘汰。其理由是:最早調入主存的頁面不再被使用的可能性最大。
訪問頁面 | 7 | 0 | 1 | 2 | 0 | 3 | 0 | 4 | 2 | 3 | 0 | 3 | 2 | 1 | 2 | 0 | 1 | 7 | 0 | 1 |
物理塊1 | 7 | 7 | 7 | 2 | 2 | 2 | 4 | 4 | 4 | 0 | 0 | 0 | 7 | 7 | 7 | |||||
物理塊2 | 0 | 0 | 0 | 3 | 3 | 3 | 2 | 2 | 2 | 1 | 1 | 1 | 0 | 0 | ||||||
物理塊3 | 1 | 1 | 1 | 0 | 0 | 0 | 3 | 3 | 3 | 2 | 2 | 2 | 1 | |||||||
缺頁否 | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
這里仍用上面的實例,釆用FIFO算法進行頁面置換。進程訪問頁面2時,把最早進入內存的頁面7換出。然后訪問頁面3時,再把2, 0, 1中最先進入內存的頁換出。由圖 3-27可以看出,利用FIFO算法時進行了 12次頁面置換,比最佳置換算法正好多一倍。
FIFO算法還會產生當所分配的物理塊數增大而頁故障數不減反增的異常現象,這是由 Belady於1969年發現,故稱為Belady異常,如圖3-28所示。只有FIFO算法可能出現Belady 異常,而LRU和OPT算法永遠不會出現Belady異常。
訪問頁面 | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
物理塊1 | 1 | 1 | 1 | 4 | 4 | 4 | 5 | ,5' | 5 | |||
物理塊2 | 2 | 2 | 2 | 1 | 1 | 1 | 3 | 3 | ||||
物理塊3 | 3 | 3 | 3 | 2 | 2 | 2 | 4 | |||||
缺頁否 | √ | √ | √ | √ | √ | √ | √ | √ | √ | |||
1 | 1 | 1 | 5 | 5 | 5 | 5 | 4 | 4 | ||||
物理塊2* | 2 | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 5 | |||
物理塊3* | 3 | 3 | 3 | 3 | 2 | 2 | 2 | 2 | ||||
物理塊4* | 4 | 4 | 4 | 4 | 3 | 3 | 3 | |||||
缺頁否 | √ | √ | √ | √ | √ | √ | √ | √ | √ |
3.最近最久未使用(LRU)算法:這種算法的基本思想是:利用局部性原理,根據一個作業在執行過程中過去的頁面訪問歷史來推測未來的行為。它認為過去一段時間里不曾被訪問過的頁面,在最近的將來可能也不會再被訪問。所以,這種算法的實質是:當需要淘汰一個頁面時,總是選擇在最近一段時間內最久不用的頁面予以淘汰。
再對上面的實例釆用LRU算法進行頁面置換,如圖3-29所示。進程第一次對頁面2訪問時,將最近最久未被訪問的頁面7置換出去。然后訪問頁面3時,將最近最久未使用的頁面1換出。
訪問頁面 | 7 | 0 | 1 | 2 | 0 | 3 | 0 | 4 | 2 | 3 | 0 | 3 | 2 | 1 | 2 | 0 | 1 | 7 | 0 | 1 |
物理塊1 | 7 | 7 | 7 | 2 | 2 | 4 | 4 | 4 | 0 | 1 | 1 | 1 | ||||||||
物理塊2 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 3 | 3 | 0 | 0 | |||||||||
物理塊3 | 1 | 1 | 3 | 3 | 2 | 2 | 2 | 2 | 2 | 7 | ||||||||||
缺頁否 | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
實際上,LRU算法根據各頁以前的情況,是“向前看”的,而最佳置換算法則根據各頁以后的使用情況,是“向后看”的。
***LRU性能較好,但需要寄存器和棧的硬件支持。LRU是堆棧類的算法。理論上可以證明,堆棧類算法不可能出現Belady異常。FIFO算法基於隊列實現,不是堆棧類算法。
4. 時鍾(CLOCK)置換算法
LRU算法的性能接近於OPT,但是實現起來比較困難,且開銷大;FIFO算法實現簡單,但性能差。所以操作系統的設計者嘗試了很多算法,試圖用比較小的開銷接近LRU的性能,這類算法都是CLOCK算法的變體。
簡單的CLOCK算法是給每一幀關聯一個附加位,稱為使用位。當某一頁首次裝入主存時,該幀的使用位設置為1;當該頁隨后再被訪問到時,它的使用位也被置為1。對於頁替換算法,用於替換的候選幀集合看做一個循環緩沖區,並且有一個指針與之相關聯。當某一頁被替換時,該指針被設置成指向緩沖區中的下一幀。當需要替換一頁時,操作系統掃描緩沖區,以查找使用位被置為0的一幀。每當遇到一個使用位為1的幀時,操作系統就將該位重新置為0;如果在這個過程開始時,緩沖區中所有幀的使用位均為0,則選擇遇到的第一個幀替換;如果所有幀的使用位均為1,則指針在緩沖區中完整地循環一周,把所有使用位都置為0,並且停留在最初的位置上,替換該幀中的頁。由於該算法循環地檢查各頁面的情況,故稱為CLOCK算法,又稱為最近未用(Not Recently Used, NRU)算法。
CLOCK算法的性能比較接近LRU,而通過增加使用的位數目,可以使得CLOCK算法更加高效。在使用位的基礎上再增加一個修改位,則得到改進型的CLOCK置換算法。這樣,每一幀都處於以下四種情況之一:
- 最近未被訪問,也未被修改(u=0, m=0)。
- 最近被訪問,但未被修改(u=1, m=0)。
- 最近未被訪問,但被修改(u=0, m=1)。
- 最近被訪問,被修改(u=1, m=1)。
算法執行如下操作步驟:
- 從指針的當前位置開始,掃描幀緩沖區。在這次掃描過程中,對使用位不做任何修改。選擇遇到的第一個幀(u=0, m=0)用於替換。
- 如果第1)步失敗,則重新掃描,查找(u=0, m=1)的幀。選擇遇到的第一個這樣的幀用於替換。在這個掃描過程中,對每個跳過的幀,把它的使用位設置成0。
- 如果第2)步失敗,指針將回到它的最初位置,並且集合中所有幀的使用位均為0。重復第1步,並且如果有必要,重復第2步。這樣將可以找到供替換的幀。
改進型的CLOCK算法優於簡單CLOCK算法之處在於替換時首選沒有變化的頁。由於修改過的頁在被替換之前必須寫回,因而這樣做會節省時間。
例題:
*在5個頁框上使用LRU頁面替換算法,當頁框初始為空時,引用序列為0、1、7、8、6、2、3、7、2、9、8、1、0、2,系統將發生(C)次缺頁
A、13 B、12 C、11 D、8
解析:內存中駐留5個頁框:
訪問頁面 | 0 | 1 | 7 | 8 | 6 | 2 | 3 | 7 | 2 | 9 | 8 | 1 | 0 | 2 |
頁框1 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
頁框2 | 1 | 1 | 1 | 1 | 1 | 3 | 3 | 3 | 3 | 3 | 1 | 1 | 1 | |
頁框3 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 0 | 0 | ||
頁框4 | 8 | 8 | 8 | 8 | 8 | 8 | 9 | 9 | 9 | 9 | 9 | |||
頁框5 | 6 | 6 | 6 | 6 | 6 | 6 | 8 | 8 | 8 | 8 | ||||
是否缺頁 | Y | Y | Y | Y | Y | Y(換頁) | Y(換頁) | N | N | Y(換頁) | Y(換頁) | Y(換頁) | Y(換頁) | N |
LRU是堆棧類的算法,最后訪問的頁面放在棧頂,可以得到答案為C。
編程思路:
1,用結構體成員記錄訪問的順序,換頁時選取times最大的那個替換掉。
struct LRU { int data;
int times;};記錄訪問次序
struct queue{ LRU *p; int front; int rear
}Qe;
(1)隊列未滿時,依次添加新訪問的頁面,並Qe.p[i++].times++
(2)隊列滿了 a, 新訪問的頁面在隊列中,times設為0,之前在它前面的LRU.times++
b, 新訪問的頁面不在隊列中,需替換掉times最大的頁面,並設新頁面times=0,對列中其它頁面times++
2,用隊列中存放的位置表示最后訪問時間(用線性表涉及大量元素移動,用鏈表好些)
隊列未滿時,依次壓入;隊列滿,則查看對列中是否存在,若存在,將其移動到隊尾,若不存在,刪除隊首頁面,並在隊尾加入新頁面。
C++代碼實現: