1. 程式人生 > >實驗五 虛擬記憶體頁面置換演算法

實驗五 虛擬記憶體頁面置換演算法

一、  需求分析

說明程式設計的任務和目的,明確規定下述內容:

加深對虛擬記憶體頁面置換概念的理解,進一步掌握先進先出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

int visitCount;    //頁面檔案在記憶體中的訪問次數

}

記憶體物件

classRAM

{

publicint breakCount;//中斷次數

publicint size;//記憶體可存放頁面檔案的總個數

publicint freeSize;//空閒個數

publicint freePostion;//置換過程中臨時留下的空位索引[預設-2,無空位時為-1]

publicList<Page> RAMDetail;//記憶體中頁面檔案的狀態

}

三、  詳細設計

實現程式模組的具體演算法。

publicPage GetPageofLongest()

publicPage GetPageofRecentUnused(

string[] orders,int currentOrderIndex)

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();
        }
    }
}




七、  附錄

帶註釋的源程式,註釋應清楚具體;