模拟请求分页式存储管理 ---4种置换算法
請求調頁+頁面置換
1.虛擬存儲系統
操作系統中,為了提高內存利用率,提供了內外存進程對換機制;內存空間的分配和回收均以頁為單位進行;一個進程只需將其一部分(段或頁)調入內存便可運行;還支持請求調頁的存儲管理方式。
當進程在運行中需要訪問某部分程序和數據時,發現其所在頁面不在內存,就立即提出請求(向CPU發出缺中斷),由系統將其所需頁面調入內存。這種頁面調入方式叫請求調頁。
?
2. 頁面置換過程
當CPU接收到缺頁中斷信號,中斷處理程序先保存現場,分析中斷原因,轉入缺頁中斷處理程序。該程序通過查找頁表,得到該頁所在外存的物理塊號。如果此時內存未滿,能容納新頁,則啟動磁盤I/O將所缺之頁調入內存,然后修改頁表。如果內存已滿,則須按某種置換算法從內存中選出一頁準備換出,是否重新寫盤由頁表的修改位決定,然后將缺頁調入,修改頁表。利用修改后的頁表,去形成所要訪問數據的物理地址,再去訪問內存數據。整個頁面的調入過程對用戶是透明的。
?
(1)?? 頁表:放在系統空間的頁表區,存放邏輯頁與物理頁幀的對應關系。 每一個進程都擁有一個自己的頁表,PCB表中有指針指向頁表。
(2)?? 頁框:RAM塊,來描述物理內存空間,由操作系統實現從邏輯頁到物理頁框的頁面映射,同時負責對所有頁的管理和進程運行的控制。模擬時對于頁框的分配數量自主設定。
(3)?? 訪問位:不論是讀還是寫(get or set),系統都會設置該頁的訪問位,記錄本頁在一段時間內被訪問的次數,或最近已有多長時間未被訪問,它的值用來幫助操作系統在發生缺頁中斷時選擇要被淘汰的頁,即用于頁面置換。
(4)?? 修改位(臟位):用于頁面的換出,如果某個頁面被修改過(即為臟),在淘汰該頁時,必須將其寫回磁盤,反之,可以直接丟棄該頁。
(5) 有效位(駐留位、中斷位):表示該頁是內存還是磁盤。
(6) 保護位:存取控制位,用于指出該頁允許什么類型的訪問,如果用一位來標識的話:1表示只讀,0表示讀寫。
?
1.LRU
least recently used 最近時間內 最久未被使用的頁面被置換
如果一個數據在最近一段時間沒有被訪問到,那么在將來它被訪問的可能性也很小,拿“最近的過去”預測“最近的未來”。
LRU算法的硬件支持
LRU算法雖然是一種比較好的算法,但是要求系統有較多的支持硬件。為了了解一個進程在內存中的各個頁面各有多少時間未被進程訪問,以及如何快速得知道哪一頁是最近最久未使用的頁面,須有寄存器和棧兩類硬件之一的支持。?
1)寄存器?
為了記錄某進程在內存中各頁的使用情況,須為每個內存中的頁面配置一個移位寄存器,可表示為?
當進程訪問某物理塊時,要將相應的寄存器的Rn?1位置成1。此時,定時信號將每隔一定時間將寄存器右移一位。如果我們把n位寄存器的數看作是一個整數,那么,具有最小數值的寄存器所對應的頁面,就是最近最久未使用的頁面。 (e.g. 每100ms右移一位,最高位補0還是補1的問題)
2)棧?
可利用一個特殊的棧保持當前使用的各個頁面的頁面號。每當進程訪問某頁面是,便將該頁面的頁面號從棧中移出,將它壓入棧頂。因此,棧頂始終是最近最久未使用頁面的頁面號。
模擬實現2:
采用雙向鏈表+heapmap配合實現,靠近鏈表頭部的越是最近訪問過得,鏈表尾部是最久未被訪問的,從而體現使用的時間順序,heapmap記錄表項地址。
過程:
要操作頁面K
?????? 未在內存 1.內存未滿->直接插入鏈表頭部,記錄地址
???????????????????? ? 2.內存已滿->先刪除鏈表尾部節點,再插入新節點到鏈表頭部,并且更新map中增加該節點
?????? 已在內存:更新節點的值,把當前訪問的節點移到鏈表頭部,并且更新map中該節點的地址。
class LRUBlock{ public:LRUBlock(int capacity) {size = capacity;}/**操作頁面k*/void set(int blockId,int k) {///未在內存if(blockMap.find(k) == blockMap.end()){if(blockList.size() == size){///刪除鏈表尾部節點(最少訪問的節點) blockMap.erase(blockList.back().pageId);blockList.pop_back();}///插入新節點到鏈表頭部,并且更新map中增加該節點 blockList.push_front(BlockNode(blockId,k));blockMap[k] = blockList.begin();}///已在內存else{///更新節點的值,把當前訪問的節點移到鏈表頭部,并且更新map中該節點的地址 blockList.splice(blockList.begin(), blockList, blockMap[k]);blockMap[k] = blockList.begin();}}list<BlockNode> getList(){return this->blockList;} private:list<BlockNode> blockList;unordered_map<int, list<BlockNode>::iterator> blockMap;///記錄結點地址int size; };?
void LRU(LRUBlock&lru,int address,map<int,TableEntry>&pageTable,map<int,int>&memoryBlock) {int pageNum=address/unitBlockSize;if(pageTable[pageNum].entryStatus==1){cout<<"頁面已在內存中\n";lru.set(pageTable[pageNum].blockId,pageNum);}else{int s=memoryBlock.size();if(memoryBlock[s-1]==1){///直接分cout<<"所分配內存塊還未用完\n";int i=s-1;for(;i>=0;i--){if(memoryBlock[i]==0)break;}memoryBlock[i+1]=0;pageTable[pageNum].entryStatus=1;pageTable[pageNum].blockId=i+1;lru.set(i+1,pageNum);}else///先swap再分 {cout<<"所分配內存塊全被占用,需要置換操作\n";BlockNode blockNode=lru.getList().back();cout<<"置換出"<<blockNode.pageId<<"\t置換入"<<pageNum<<endl;///搶pageTable[blockNode.pageId].entryStatus=0;pageTable[blockNode.pageId].blockId=-1;pageTable[pageNum].entryStatus=1;pageTable[pageNum].blockId=blockNode.blockId;lru.set(blockNode.blockId,pageNum);}pageBreak++;}total++; }?
2.LFU:
least frequently used 最少使用置換
如果一個數據在最近一段時間內使用次數很少,那么在將來一段時間內被使用的可能性也很小,LRU的淘汰規則是基于訪問時間,而LFU是基于訪問次數的。
注意:
一般情況下,LFU效率要優于LRU,且能夠避免周期性或者偶發性的操作導致緩存命中率下降的問題。但LFU需要記錄數據的歷史訪問記錄,一旦數據訪問模式改變,LFU需要更長時間來適用新的訪問模式,即:LFU存在歷史數據影響將來數據的“緩存污染”效用。
實現:
用數組存儲內存中表項情況,通過遍歷查找最小值。
過程:
要操作頁面K
?????? 未在內存 1.內存未滿:更新頁表,表項放入數組。
???????????????????? ? 2.內存已滿:更新頁表,數組刪除要淘汰的表項,加入新表項。
?????? 已在內存:更新頁表,表項重新放入數組。
3.FIFO
first in first out 最早出現置換
隊列實現
過程:
已在內存:none
不在內存:
內存未滿:表項加入隊尾
內存已滿:pop隊首,新表項加入隊尾
4.CLOCK
NRU---Not Recently Used
用數組存儲內存中表項情況,修改數組中表項訪問情況選擇置出頁面。
置換策略:依次訪問數組中的表項,遇到status=1的置為0,再給一次駐留內存的機會,遇到status=0的換出。
過程:
已在內存:none
不在內存:
內存未滿:表項加入數組
內存已滿:拿新來表項替換置出表項
?
?
?
轉載于:https://www.cnblogs.com/kimsimple/p/7065929.html
總結
以上是生活随笔為你收集整理的模拟请求分页式存储管理 ---4种置换算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷 P2046 BZOJ 2007 海
- 下一篇: 1191 数轴染色