1. 程式人生 > >作業系統之頁面置換演算法

作業系統之頁面置換演算法

地址對映過程中,若在頁面中發現所要訪問的頁面不在記憶體中,則產生缺頁中斷。當發生缺頁中斷時,如果作業系統記憶體中沒有空閒頁面,則作業系統必須在記憶體選擇一個頁面將其移出記憶體,以便為即將調入的頁面讓出空間。而用來選擇淘汰哪一頁的規則叫做頁面置換演算法。

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置換演算法。這樣,每一幀都處於以下四種情況之一:

  1. 最近未被訪問,也未被修改(u=0, m=0)。
  2. 最近被訪問,但未被修改(u=1, m=0)。
  3. 最近未被訪問,但被修改(u=0, m=1)。
  4. 最近被訪問,被修改(u=1, m=1)。


演算法執行如下操作步驟:

  1. 從指標的當前位置開始,掃描幀緩衝區。在這次掃描過程中,對使用位不做任何修改。選擇遇到的第一個幀(u=0, m=0)用於替換。
  2. 如果第1)步失敗,則重新掃描,查詢(u=0, m=1)的幀。選擇遇到的第一個這樣的幀用於替換。在這個掃描過程中,對每個跳過的幀,把它的使用位設定成0。
  3. 如果第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,用佇列中存放的位置表示最後訪問時間(用線性表涉及大量元素移動,用連結串列好些)

佇列未滿時,依次壓入;佇列滿,則檢視對列中是否存在,若存在,將其移動到隊尾,若不存在,刪除隊首頁面,並在隊尾加入新頁面。