實驗五 虛擬記憶體頁面置換演算法
一、 需求分析
說明程式設計的任務和目的,明確規定下述內容:
加深對虛擬記憶體頁面置換概念的理解,進一步掌握先進先出FIFO、最佳置換OPI和最近最久未使用LRU頁面置換演算法的實現方法。
(1) 輸入的形式和輸入值的範圍;
輸入1-3的整數選擇演算法
已在程式中預置好頁面資訊和頁面訪問順序
(2) 輸出的形式;
頁面置換的過程和置換後記憶體的狀態
(3) 程式所能達到的功能;
模擬先出FIFO、最佳置換OPI和最近最久未使用LRU頁面置換演算法
(4) 測試資料,包括正確的輸入及其輸出結果和含有錯誤的輸入及其輸出結果。
依次輸入1 2 3選擇相應演算法
輸出置換過程
二、 概要設計
說明本程式中用到的所有抽象資料型別的定義、主程式的流程以及各程式模組之間的層次(呼叫)關係。
頁面檔案物件
classPage
{
publicstring id;//頁面檔案id
publicstring name;//頁面檔名稱
publicint timeInRAM;//頁面檔案在記憶體中的 時間
publicint comeInTime;//頁面檔案在記憶體中的 進入記憶體的時間
publicintlatestVisitTimeInPast;//頁面檔案在記憶體中的最近的訪問時間
publicint timeSpanToVisit;//該頁面在將來第一次訪問 到現在的時間間隔
public
}
記憶體物件
classRAM
{
publicint breakCount;//中斷次數
publicint size;//記憶體可存放頁面檔案的總個數
publicint freeSize;//空閒個數
publicint freePostion;//置換過程中臨時留下的空位索引[預設-2,無空位時為-1]
publicList<Page> RAMDetail;//記憶體中頁面檔案的狀態
}
三、 詳細設計
實現程式模組的具體演算法。
publicPage GetPageofLongest()
publicPage GetPageofRecentUnused(
publicPage GetPageofLastUseInfutrue(string[] orders ,int currentOrderIndex)
四、 除錯分析
(1) 除錯過程中遇到的問題以及解決方法,設計與實現的回顧討論和分析;
開始時對最近最久未使用演算法理解不清楚,導致執行結果正確。以後在編寫程式前應對演算法充分理解在進行程式設計,防止時間浪費
五、 使用者使用說明
程式的使用說明,列出每一步的操作步驟。
執行程式--選擇演算法--檢視結果
六、 測試結果
列出測試結果,包括輸入和輸出。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lab5
{
//頁面檔案
class Page
{
public string id;//頁面檔案id
public string name;//頁面檔名稱
public int timeInRAM;//頁面檔案在記憶體中的 時間
public int comeInTime;//頁面檔案在記憶體中的 進入記憶體的時間
public int latestVisitTimeInPast;//頁面檔案在記憶體中的 最近的訪問時間
public int timeSpanToVisit;//該頁面在將來第一次訪問 到現在的時間間隔
public int visitCount; //頁面檔案在記憶體中的 訪問次數
public Page(string id, string name)
{
this.id = id;
this.name = name;
timeInRAM = 0;
visitCount = 0;
comeInTime = -1;
latestVisitTimeInPast = int.MinValue;
timeSpanToVisit = int.MaxValue;
}
//頁面檔案進入記憶體
public void ComeInRAM(int time)
{
comeInTime = time;
latestVisitTimeInPast = comeInTime;
timeInRAM++;
VistInRAM(time);//進入時訪問次數增加
}
//頁面檔案停留在記憶體中
public void StayInRAM()
{
timeInRAM++;
}
//頁面檔案被移出記憶體
public void GoOutRAM()
{
comeInTime = -1;
timeInRAM=0;
visitCount = 0;
}
//在記憶體中被訪問
public void VistInRAM(int time)
{
latestVisitTimeInPast = comeInTime;
visitCount++;
}
public void Print()
{
Console.Write(name ); //Console.Write(name + "[" + id + "]");
}
}
class RAM
{
public int breakCount;//中斷次數
public int size;//記憶體可存放頁面檔案的總個數
public int freeSize;//空閒個數
public int freePostion;//置換過程中臨時留下的空位索引[預設-2,無空位時為-1]
public List<Page> RAMDetail;//記憶體中頁面檔案的狀態
public RAM(int size)
{
this.size = size;
freeSize = size;
RAMDetail = new List<Page>();
freePostion = -2;
breakCount = 0;
}
public void PrintPageState()
{
if (size != RAMDetail.Count+freeSize)
{
Console.WriteLine("資料有誤");
return;
}
for (int i = 0; i < RAMDetail.Count; i++)
{
RAMDetail[i].Print();
}
}
//新進入頁面檔案
public void ComeIn(Page page,int time)
{
page.ComeInRAM(time);
if( freePostion == -2)
{
RAMDetail.Add(page);
}
else
{
RAMDetail.Insert(freePostion,page);
}
freeSize--;
if(freeSize==0)
{
freePostion = -1;
}
Console.WriteLine("\n---正在將[" + page.name + "]裝入記憶體...\n");
}
//丟棄頁面檔案
public void GoOut(Page page)
{
page.GoOutRAM();
freePostion = GetIndexById(page.id);//找到位置
RAMDetail.RemoveAt(freePostion);
freeSize++;
Console.WriteLine("\n---正在將[" + page.name + "]移出記憶體...\n");
}
//不置換頁面時呼叫
public void FinishChage()
{
for (int k = 0; k < RAMDetail.Count; k++)
{
RAMDetail[k].StayInRAM();
}
PrintPageState(); Console.WriteLine("");
}
public bool IsInRAM(Page page)
{
return (from t in RAMDetail
where t.id == page.id
select t).FirstOrDefault() == null ? false : true;
}
//1-【FIFO】先進先出 獲取最先進入的(在記憶體中待的時間最長)
public Page GetPageofLongest()
{
int maxValue = 0;
int maxIndex = 0;
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].timeInRAM > maxValue)
{
maxIndex = i;
maxValue = RAMDetail[i].timeInRAM;
}
}
return RAMDetail[maxIndex];
}
//2-【LRU】最近最久 //往當前序列向前看 n-1個,如果記憶體中的頁面檔案出現了,則從快取中移出,若均未出現,則找出最先進入的返回
public Page GetPageofRecentUnused( string[] orders,int currentOrderIndex)
{
//建立快取
List<Page> temp = new List<Page>(RAMDetail);
//查詢歷史訪問
int start = currentOrderIndex - 1;
int end=start - (size - 1)+1;
for (int i = start; i >= end; i--)
{
//判斷該頁是否在記憶體中
int index=GetIndexById(orders[i]);
//如果在記憶體中
if (index != -1)
{//從快取中刪除
temp.Remove(Tool.GetPageById(RAMDetail, orders[i]));
}
}
//快取中剩餘數量大於1
return temp.Count > 1 ? Tool.GetPageofLongest(temp) : temp[0];
}
//3-【OPT】最佳 根據請求序列找出 最後使用的那個移出
public Page GetPageofLastUseInfutrue(string[] orders ,int currentOrderIndex)
{
//將來再也不會被請求的頁面集合
List<Page> dontShowPageList = new List<Page>();
int start = currentOrderIndex + 1;
int end = orders.Length-1;
for (int i = 0; i < RAMDetail.Count;i++ )
{
bool pageWiilUse = false;
Page currentPage=RAMDetail[i];
//該頁面在將來第一次訪問 到現在的時間間隔
int timeSpanToVisit = 1;
for (int j = start; j < end; j++)
{
//計算間隔
if(currentPage.id==orders[j])
{
currentPage.timeSpanToVisit = timeSpanToVisit;
break;
}
else
{
timeSpanToVisit++;
}
}
//遍歷完序列都沒找到,加入集合
if (timeSpanToVisit == end-start+1)
dontShowPageList.Add(currentPage);
}
//如果不需要的少於1個
if (dontShowPageList.Count <=1 )
{
//找出最timeSpanToVisit最大的返回
int maxValue =int.MaxValue;
int maxIndex = -1;
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].timeSpanToVisit >= maxValue)
{
maxValue = RAMDetail[i].timeSpanToVisit;
maxIndex = i;
}
}
return RAMDetail[maxIndex];
}
else
{//否則在不需要中找到待的最久的
return Tool.GetPageofLongest(dontShowPageList);
}
}
//獲取最先進入的(在記憶體中待的時間最長)
public int GetIndexById(string id)
{
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].id == id)
{
return i;
}
}
return -1;
}
public void processPage(List<Page> pageList, string[] orders,string flag="1")
{
Console.Write(" \n執行過程如下: \n");
//計時器
int time = 0;
//按id順序訪問頁面
for (int i = 0; i < orders.Length; i++)
{
Console.WriteLine("\n------------------正在請求[" + Tool.GetPageById(pageList, orders[i]).name + "]... \n");
time++;
Page currentPage = Tool.GetPageById(pageList, orders[i]);
//有空位
if (freeSize > 0)
{
//新來的進入
ComeIn(currentPage, time);
//結束置換
FinishChage();
}
else
{//沒空位
//如果沒在RAM中,置換頁面併產生中斷
if (!IsInRAM(currentPage))
{
//中斷
breakCount++;
switch (flag)
{
case "1":
{
//1先進先出(在記憶體中待的時間最長的先出去)
GoOut(GetPageofLongest());
}
break;
case "2":
{
//2最近最久未使用
GoOut(GetPageofRecentUnused(orders, i));
}
break;
case "3":
{
//3最優
GoOut(GetPageofLastUseInfutrue(orders, i));
}
break;
default: Console.WriteLine("輸入有誤,程式即將終止!"); break;
}
//新來的進入
ComeIn(currentPage, time);
//結束置換
FinishChage();
}
else
{//如果在RAM中,不置換,全都待在記憶體中
currentPage.VistInRAM(time);
FinishChage();
}
}
}
}
}
class Tool
{
public static Page GetPageById(List<Page> pageList,string id)
{
return pageList.Where(m => m.id == id).FirstOrDefault();
}
public static void PrintPageList(List<Page> pageList)
{
Console.Write(" \n頁面檔案如下: \n");
for (int i = 0; i < pageList.Count; i++)
{
pageList[i].Print(); Console.Write(" ");
}
Console.Write("\n");
}
public static void PrintOrders(string[] orders)
{
Console.Write(" \n頁面訪問順序[頁面ID]如下: \n");
for (int i = 0; i < orders.Length; i++)
{
Console.Write(orders[i]+" ");
}
Console.Write("\n");
}
public static Page GetPageofLongest(List<Page> pageList)
{
int maxValue = 0;
int maxIndex = 0;
for (int i = 0; i < pageList.Count; i++)
{
if (pageList[i].timeInRAM > maxValue)
{
maxIndex = i;
maxValue = pageList[i].timeInRAM;
}
}
return pageList[maxIndex];
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("----------虛擬記憶體頁面置換演算法----------- ");
List<Page> pageList = new List<Page>();
pageList.Add(new Page("0", "頁面0"));
pageList.Add(new Page("1","頁面1"));
pageList.Add(new Page("2", "頁面2"));
pageList.Add(new Page("3", "頁面3"));
pageList.Add(new Page("4", "頁面4"));
pageList.Add(new Page("5", "頁面5"));
pageList.Add(new Page("6", "頁面6"));
string[] orders = new string[] { "6", "0", "1", "2", "0", "3", "0", "4", "2", "3" };
Tool.PrintPageList(pageList);
Tool.PrintOrders(orders);
RAM ram = new RAM(3);
Console.Write(" \n選擇演算法: 1-【FIFO】先進先出 2-【LRU】最近最久 3-【OPT】最佳 \n");
ram.processPage(pageList, orders,Console.ReadLine());
Console.ReadLine();
}
}
}
七、 附錄
帶註釋的源程式,註釋應清楚具體;