操作系統頁面置換算法(opt,lru,fifo,clock)實現

? ? ? ?選擇調出頁面的算法就稱為頁面置換算法。好的頁面置換算法應有較低的頁面更換頻率,也就是說,應將以后不會再訪問或者以后較長時間內不會再訪問的頁面先調出。

常見的置換算法有以下四種(以下來自操作系統課本)。

1. 最佳置換算法(OPT)

最佳(Optimal, 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。

訪問頁面70120304230321201701
物理塊17772?2?2??2??2???7??
物理塊2?000?0?4??0??0???0??
物理塊3??11?3?3??3??1???1??
缺頁否????????????
圖3-26 ?利用最佳置換算法時的置換圖

2. 先進先出(FIFO)頁面置換算法

優先淘汰最早進入內存的頁面,亦即在內存中駐留時間最久的頁面。該算法實現簡單,只需把調入內存的頁面根據先后次序鏈接成隊列,設置一個指針總指向最早的頁面。但該算法與進程實際運行時的規律不適應,因為在進程中,有的頁面經常被訪問。

訪問頁面70120304230321201701
物理塊17772?224440??00??777
物理塊2?000?333222??11??100
物理塊3??11?100033??32??221
缺頁否?????
圖3-27 ?利用FIFO置換算法時的置換圖
這里仍用上面的實例,釆用FIFO算法進行頁面置換。進程訪問頁面2時,把最早進入內存的頁面7換出。然后訪問頁面3時,再把2, 0, 1中最先進入內存的頁換出。由圖?3-27可以看出,利用FIFO算法時進行了?12次頁面置換,比最佳置換算法正好多一倍。

FIFO算法還會產生當所分配的物理塊數增大而頁故障數不減反增的異常現象,這是由?Belady于1969年發現,故稱為Belady異常,如圖3-28所示。只有FIFO算法可能出現Belady?異常,而LRU和OPT算法永遠不會出現Belady異常。
訪問頁面123412512345
物理塊11114445??55?
物理塊2?222111??33?
物理塊3??33322??24?
缺頁否???
??111??555544
物理塊2*?222??211115
物理塊3*??33??332222
物理塊4*???4??444333
缺頁否???
圖?3-28 ??Belady?異常

3. 最近最久未使用(LRU)置換算法

選擇最近最長時間未訪問過的頁面予以淘汰,它認為過去一段時間內未訪問過的頁面,在最近的將來可能也不會被訪問。該算法為每個頁面設置一個訪問字段,來記錄頁面自上次被訪問以來所經歷的時間,淘汰頁面時選擇現有頁面中值最大的予以淘汰。

再對上面的實例釆用LRU算法進行頁面置換,如圖3-29所示。進程第一次對頁面2訪問時,將最近最久未被訪問的頁面7置換出去。然后訪問頁面3時,將最近最久未使用的頁面1換出。

訪問頁面70120304230321201701
物理塊17772?2?4440??1?1?1??
物理塊2?000?0?0033??3?0?0??
物理塊3??11?3?3222??2?2?7??
缺頁否????????
圖3-29 ?LRU頁面置換算法時的置換圖

在圖3-29中,前5次置換的情況與最佳置換算法相同,但兩種算法并無必然聯系。實際上,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算法之處在于替換時首選沒有變化的頁。由于修改過的頁在被替換之前必須寫回,因而這樣做會節省時間。

#include <iostream>  
#include<map>
#include<set>
#include <algorithm>
#include<cstdio>
#include<cstring> 
#include<cmath>
#define N 200
using namespace std;  int page[N];//頁面引用號 
int block[N];//物理塊,內存 
int dist[N][N];//表示第i次訪問內存的時候,內存中的頁面j 在以后被訪問的最小時間 int n;//頁面引用號個數 
int m;//物理塊數目 
int page_max;//最大頁面號 int pre[N];//page[i]在page中的索引
int opt(){//最佳頁面置換算法 int page_lack = 0;memset(pre, 0, sizeof(pre));memset(dist, 0x3f, sizeof(dist));memset(block, -1, sizeof(block));for(int i=n; i>=1; --i){for(int j=0; j<=page_max; ++j) if(pre[j])dist[i][j] = pre[j] - i;pre[page[i]] = i; }for(int i=1; i<=n; ++i){//開始訪問頁面,初始是內存中沒有分頁 int j;int max_dist = 0, p; for(j=1; j<=m; ++j){if(block[j] == -1){//改塊沒有放入頁面,則直接放入, 產生缺頁 block[j] = page[i]; cout<<"頁面"<<page[i]<<"不在內存,直接放入物理塊"<<j<<"中!"<<endl;page_lack++;break;} else if(block[j] == page[i])//頁面存在內存中 break;if(max_dist < dist[i][block[j]]){max_dist = dist[i][block[j]];//說明block[j] 對應的頁面以后會長時間不會用到 p = j;//block[] 第j個頁面會被替換掉 
            }}if(j > m){//此時內存中不能在放入新的分頁,而且沒有找到page[i]對應的分頁,接下來進行頁面替換 cout<<"頁面"<<page[i]<<"不在內存,將物理塊"<<p<<"中的頁面" <<block[p]<<"替換掉!"<<endl;block[p] = page[i];page_lack++; }cout<<endl<<"當前內存中頁面的情況:"<<endl; for(int k=1; k<=m; ++k)//內存中頁面加載情況 cout<<block[k]<<" ";cout<<endl<<endl;}return page_lack;//返回缺頁次數 
} int lru(){//最近最久未使用算法和opt算法差不多,只不過是lru是向前看, opt是向后看 int page_lack = 0;memset(pre, 0, sizeof(pre));memset(dist, 0x3f, sizeof(dist));memset(block, -1, sizeof(block));for(int i=1; i<=n; ++i){for(int j=0; j<=page_max; ++j) if(pre[j])dist[i][j] = i - pre[j];pre[page[i]] = i; }for(int i=1; i<=n; ++i){//開始訪問頁面,初始是內存中沒有分頁 int j;int max_dist = 0, p; for(j=1; j<=m; ++j){if(block[j] == -1){//改塊沒有放入頁面,則直接放入, 產生缺頁 block[j] = page[i]; cout<<"頁面"<<page[i]<<"不在內存,直接放入物理塊"<<j<<"中!"<<endl;page_lack++;break;} else if(block[j] == page[i])//頁面存在內存中 break;if(max_dist < dist[i][block[j]]){max_dist = dist[i][block[j]];//說明block[j] 對應的頁面以后會長時間不會用到 p = j;//block[] 第j個頁面會被替換掉 
            }}if(j > m){//此時內存中不能在放入新的分頁,而且沒有找到page[i]對應的分頁,接下來進行頁面替換 cout<<"頁面"<<page[i]<<"不在內存,將物理塊"<<p<<"中的頁面" <<block[p]<<"替換掉!"<<endl;block[p] = page[i];page_lack++; }cout<<endl<<"當前內存中頁面的情況:"<<endl; for(int k=1; k<=m; ++k)//內存中頁面加載情況 cout<<block[k]<<" ";cout<<endl<<endl;}return page_lack;//返回缺頁次數 
} set<int>page_set;
int fifo(){//先進先出頁面置換算法int page_lack = 0; memset(block, -1, sizeof(block));int index = 1;for(int i=1; i<=n; ++i){if(index > m) index = 1;set<int>::iterator it;it = page_set.find(page[i]);  if(it == page_set.end()){if(block[index] != -1)page_set.erase(block[index]);page_set.insert(page[i]);block[index++] = page[i];++page_lack;} for(int k=1; k<=m; ++k)cout<<block[k]<<" ";cout<<endl;} return page_lack;
}int nru[N];//表示 物理塊 i 最近時候被訪問過 
int page_in_block[N];//頁面 i 在 block的下標索引 
int clock(){int index = 1;int page_lack = 0;memset(block, -1, sizeof(block));for(int i=1; i<=n; ++i){if(page_in_block[page[i]]){//如果page[i]已經在內存中 nru[page_in_block[page[i]]] = 1;//重新標記這個物理塊中的頁面被訪問過了 cout<<endl<<""<<i<<"次: 頁面"<<page[i]<<"已經存在物理塊"<< page_in_block[page[i]] << "中!"<<endl;}else {while(true){if(index > m) index = 1;if(block[index] == -1) {nru[index] = 1;page_in_block[page[i]] = index;block[index++] = page[i];++page_lack;break;}if(block[index] == page[i]){nru[index++] = 1;break;} else {if(nru[index] == 0){//替換該頁面 nru[index] = 1;page_in_block[block[index]] = 0;cout<<endl<<""<<i<<"次: 物理塊"<<index<<"中的頁面"<< block[index] <<"最近未被使用,將要被頁面"<<page[i]<<"替換!"<<endl;page_in_block[page[i]] = index;block[index++] = page[i];++page_lack;break;} elsenru[index++] = 0;}} }for(int k=1; k<=m; ++k)    cout<<block[k]<<" ";cout<<endl;}return page_lack;
}int main(){cin>>n>>m;for(int i=1; i<=n; ++i){ cin>>page[i];page_max = max(page_max, page[i]) ;} cout<<"opt缺頁中斷次數:"<<opt()<<endl;cout<<"***********************************"<<endl;cout<<"lru缺頁中斷次數:"<<lru()<<endl;cout<<"***********************************"<<endl;cout<<"fifo缺頁中斷次數:"<<fifo()<<endl;cout<<"***********************************"<<endl;cout<<"clock缺頁中斷次數:"<<clock()<<endl;return 0;
} 
/*
20 3
7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 112 3
2 3 2 1 5 2 4 5 3 2 5 2
*/ 

?

轉載于:https://www.cnblogs.com/hujunzheng/p/4831007.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/531417.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/531417.shtml
英文地址,請注明出處:http://en.pswp.cn/news/531417.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(六)Linux之設備驅動模型(續)

前面我們學習了雜項設備驅動模型、早期經典字符設備驅動模型,這一小節來講解Linux中的標準字符設備驅動。 目錄&#xff08;一&#xff09;為什么引入標準字符設備驅動模型&#xff08;二&#xff09;相關接口&#xff08;三&#xff09;注冊流程&#xff08;四&#xff09;程序…

N個數依次入棧,出棧順序有多少種?

對于每一個數來說&#xff0c;必須進棧一次、出棧一次。我們把進棧設為狀態‘1’&#xff0c;出棧設為狀態‘0’。n個數的所有狀態對應n個1和n個0組成的2n位二進制數。由于等待入棧的操作數按照1‥n的順序排列、入棧的操作數b大于等于出棧的操作數a(a≤b)&#xff0c;因此輸出序…

(七)linux函數接口的使用

前面我們講解了字符設備的驅動模型&#xff0c;有了前面的基礎后&#xff0c;今天學習函數接口就比較容易了 目錄&#xff08;一&#xff09;open函數接口&#xff08;二&#xff09;read函數接口&#xff08;三&#xff09;lseek函數接口&#xff08;四&#xff09;用戶空間和…

(八)linux驅動之ioctl的使用

這篇文章給大家講解一下ioctl的簡單使用&#xff0c;關于ioctl更詳細的教程后面有機會單獨寫出來 &#xff08;一&#xff09;什么是ioctl ioctl是設備驅動程序中對設備的I/O通道進行管理的函數。所謂對I/O通道進行管理&#xff0c;就是對設備的一些特性進行控制&#xff0c;例…

(九)linux中斷編程

目錄&#xff08;一&#xff09;linux中斷的介紹&#xff08;二&#xff09;內核中斷的操作過程&#xff08;三&#xff09;實例代碼&#xff08;一&#xff09;linux中斷的介紹 linux內核中的中斷通過中斷子系統來管理。linux系統中有專門的中斷子系統&#xff0c;原理很復雜…

網絡爬蟲(1)

參考&#xff1a;http://www.cnblogs.com/dongkuo/p/4851735.html算法分析我們現在從需求中提取關鍵詞來逐步分析問題。 首先是“種子節點”。它就是一個或多個在爬蟲程序運行前手動給出的URL&#xff08;網址&#xff09;&#xff0c;爬蟲正是下載并解析這些種子URL指向的頁面…

(十)Linux之等待隊列

&#xff08;一&#xff09;阻塞和非阻塞 阻塞&#xff1a;執行設備操作時&#xff0c;若不能獲得資源&#xff0c;則掛起進程進入休眠直到滿足可操作的條件后再操作。 非阻塞&#xff1a;進程在不能進行設備操作時&#xff0c;并不掛起&#xff0c;它要么放棄&#xff0c;要么…

(十一)linux之poll輪詢

目錄&#xff08;一&#xff09;poll輪詢的作用&#xff08;二&#xff09;poll輪詢相關的接口&#xff08;三&#xff09;poll使用流程&#xff08;四&#xff09;實例代碼&#xff08;一&#xff09;poll輪詢的作用 以阻塞的方式打開文件&#xff0c;那么對多個文件讀寫時&a…

校驗碼(海明校驗,CRC冗余校驗,奇偶校驗)

循環冗余校驗碼 CRC碼利用生成多項式為k個數據位產生r個校驗位進行編碼,其編碼長度為nkr所以又稱 (n,k)碼. CRC碼廣泛應用于數據通信領域和磁介質存儲系統中. CRC理論非常復雜,一般書就給個例題,講講方法.現在簡單介紹下它的原理: 在k位信息碼后接r位校驗碼,對于一個給定的(n,k…

(十二)linux內核定時器

目錄&#xff08;一&#xff09;內核定時器介紹&#xff08;二&#xff09;內核定時器相關接口&#xff08;三&#xff09;使用步驟&#xff08;四&#xff09;實例代碼&#xff08;一&#xff09;內核定時器介紹 內核定時器并不是用來簡單的定時操作&#xff0c;而是在定時時…

java Proxy(代理機制)

我們知道Spring主要有兩大思想&#xff0c;一個是IoC&#xff0c;另一個就是AOP&#xff0c;對于IoC&#xff0c;依賴注入就不用多說了&#xff0c;而對于Spring的核心AOP來說&#xff0c;我們不但要知道怎么通過AOP來滿足的我們的功能&#xff0c;我們更需要學習的是其底層是怎…

(十三)linux中斷底半部分處理機制

這篇文章介紹一下linux中斷的底半部分的tasklet和workquene兩種處理機制&#xff0c;其中tasklet中不能有延時函數&#xff0c;workquene的處理函數可以加入延時操作 目錄&#xff08;一&#xff09;tasklet小任務處理機制&#xff08;1&#xff09;tasklet相關函數接口&#x…

Codeforces Round #326 (Div. 2) B. Pasha and Phone C. Duff and Weight Lifting

B. Pasha and PhonePasha has recently bought a new phone jPager and started adding his friends phone numbers there. Each phone number consists of exactly n digits. Also Pasha has a number k and two sequences of length n?/?k (n is divisible by k) a1,?a2,?…

vmware中裝的ubuntu上不了網

本文章針對橋接方式進行講解&#xff0c;如果需要另外兩種連接方式請參考文末給出的鏈接 &#xff08;一&#xff09;問題 主機和虛擬機可以相互ping通&#xff0c;但是卻不能ping網址 &#xff08;二&#xff09;解決辦法 vmware為我們提供了三種網絡工作模式&#xff0c;…

document.getElementById()與 $()區別

document.getElementById()返回的是DOM對象&#xff0c;而$()返回的是jQuery對象 什么是jQuery對象&#xff1f; ---就是通過jQuery包裝DOM對象后產生的對象。jQuery對象是jQuery獨有的&#xff0c;其可以使用jQuery里的方法。 比如&#xff1a; $("#test").html() 意…

關于gedit的編碼問題

今天由于gedit的編碼格式導致LCD顯示屏的問題&#xff0c;開始沒有想到后來才發現&#xff0c;在這記錄一下 #include <stdio.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h>…

c語言表白程序代碼

雙十一要到了&#xff0c;好激動啊&#xff01;&#xff01;&#xff01; 是時候準備出手了&#xff01; 花了一天的時間寫的表白代碼。 表示自己弱弱的..... 看了網上好多都是js寫的&#xff0c;感覺碉堡了&#xff01;js用的不熟&#xff0c;前端不好&#xff0c;java&#x…

tiny4412移植tslib庫

1、將tslib-1.4.tar.gz拷貝到虛擬機某個路徑進行解壓 2、進入解壓路徑tslib 3、執行#./autogen.sh 如果提示&#xff1a;./autogen.sh: 4: ./autogen.sh: autoreconf: not found 原因&#xff1a;沒有安裝automake工具, 解決辦法:需要安裝此工具&#xff1a; apt-get instal…

移植QT到tiny4412開發板

目錄&#xff08;一&#xff09; 環境準備&#xff08;二&#xff09; Qt源代碼下載&#xff08;三&#xff09; 移植tslib庫&#xff08;四&#xff09;操作流程1.解壓qt源碼包2.配置編譯環境3.生成Makefile4.編譯安裝5.安裝一些庫用來支持 qt6. 添加以下內容到開發板目錄下的…

c++面試常用知識(sizeof計算類的大小,虛擬繼承,重載,隱藏,覆蓋)

一. sizeof計算結構體 注&#xff1a;本機機器字長為64位 1.最普通的類和普通的繼承 #include<iostream> using namespace std;class Parent{ public:void fun(){cout<<"Parent fun"<<endl;} }; class Child : public Parent{ public:void fun(){…