計算機操作系統實驗之頁面置換算法(C語言)

實驗目的

1、瞭解內存分頁管理策略

2、掌握一些基本的頁面置換算法

實驗內容與基本要求

用C,C++等語言編寫程序,實現OPT、FIFO、LRU置換算法

頁面置換算法的基本內容

頁面置換算法是在當進程運行過程中,若其要訪問的頁面不在內存且內存已滿時,要決定將哪個頁面換出的算法。常見的頁面置換算法包括最佳置換、先進先出置換、最近最久未使用置換和Clock置換等。本次的實驗實現的算法包括最佳置換算法(OPT)、先進先出置換算法(FIFO)和最近最久未使用算法(LRU)。

頁面置換算法涉及到一些概念如下:

  • 缺頁率:當需要訪問的頁面不在內存時稱爲缺頁,此時需要將頁面調入內存。缺頁率就是要訪問的頁面不在內存中的概率。因此缺頁率=缺頁次數/要訪問的頁面總數。需要注意的是,缺頁的時候不一定需要進行頁面置換(如果內存還沒滿,直接將頁面調入內存即可)。
  • 置換率:置換就是將舊頁面調出內存,新頁面調進內存,即新頁面代替舊頁面的過程。置換率就是需要進行頁面置換的概率。所以置換率=置換次數/要訪問的頁面總數。
  • 命中率:就是要訪問的頁面恰好在內存中的概率。可以發現(缺頁率+命中率=1)。

最佳置換算法

最佳置換算法,就是所選擇內存中以後永遠不再使用,或者是在未來最長的一段時間內不再被訪問的頁面來換出。

img_1
用這種算法可以保證獲得最低的缺頁率,最低的置換次數,因此效率最高。然而在實際情況中,我們是無法知道哪個頁面是未來最長時間內不再被訪問的,所以實際上它是無法實現的。

先進先出置換算法

先進先出置換算法,就是選擇內存中最先進入內存,在內存中呆的最久的頁面來換出。它實現簡單,但是效率不高。
img_2
img_3

最近最久未使用算法

最近最久未使用算法,是選擇當前內存中,最久沒有被訪問的頁面來換出。它是希望通過過去頁面訪問的情況,來預測未來頁面的訪問情況,但是頁面過去與未來的走向之間並沒有必然的聯繫,因此它的效率也不是十分高。
img_4
img_5

實現思路

無論採用哪個算法,當進程需要訪問一個頁面時,存在三種情況:

1.頁面已經在內存中

2.頁面不在內存中,但是此時內存還未滿

3.頁面不在內存中,且此時內存已滿,需要把頁面換出

不同算法的區別主要是決定換出哪個頁面

img_6

最佳置換算法中,被換出的算法是在最長未來時間內不再被訪問的頁面。也就是說,需要計算出當前內存中頁面的下一次訪問位置,哪個頁面的下一次訪問位置最遠,就將它換出。因此需要一個數組額外記錄下次訪問位置,每當訪問完一個頁面(不管這個頁面是新換入的,還是早就在內存中的),都需要遍歷剩下的頁面號引用串,更新這個數組。

先進先出置換算法比較簡單,用一個變量記錄當前內存中最先進入頁面的下標。由於頁面都是按數組下標順序保存的,因此每訪問一個頁面,該變量就加一。等變量等於數組長度時,再重新歸零即可。

最近最久未使用算法有兩種思路:1.與最佳置換算法類似,設置一個時間數組,記錄從內存中頁面上次訪問至今的時間,哪個頁面的時間最長則將它換出。如果要訪問的頁面已在內存中,則時間歸零。當每次發起一個訪問請求,則所有頁面訪問時間加一,更新該數組。2.用數組模擬隊列的結構,隊列頭出隊列尾入,每當需要訪問新的頁面時,就將數組內的數據前移一位,新頁面加入數組最後。如果要訪問的頁面已在內存中,則用一個臨時變量記錄該頁面,然後從該頁面起的數據前移一位,把該頁面加入數組最後(課本上說是用棧的結構,但是嚴格上來說,棧只允許一端出入。因此按照課本上的功能描述,實際應該採用的結構仍是隊列)

流程圖

程序總流程圖

總流程圖

OPT算法流程圖

OPT

FIFO算法流程圖

FIFO

LRU算法流程圖

LRU

全部代碼

代碼

//
//  main.c
//  pageReplacement
//
//  Created by Apple on 2019/11/12.
//  Copyright © 2019 Yao YongXin. All rights reserved.
//

#include <stdio.h>

//初始化隊列
void initializeList(int list[],int number){
    for (int i = 0; i < number; i ++) {
        list[i] = -1;
    }
}
//展示隊列狀態
void showList(int list[], int number){
    for (int i = 0; i < number; i ++) {
        printf("%2d",list[i]);
    }
    printf("\n");
}

//展示當前內存狀態
void showMemoryList(int list[],int phyBlockNum){
    for (int i = 0; i < phyBlockNum; i ++) {
        if (list[i] == -1) {
            break;
        }
        printf(" |%d|",list[i]);
    }
    printf("\n");
}

void informationCount(int missingCount,int replaceCount,int pageNum){
    printf("缺頁次數:%d   缺頁率:%d/%d\n",missingCount,missingCount,pageNum);
    double result = (double)(pageNum - missingCount)/(double)pageNum;
    printf("置換次數:%d  命中率:%.2f\n",replaceCount,result);
}

//找到該頁面下次要訪問的位置
int getNextPosition(int currentPage,int currentPosition,int strList[],int pageNum){
    
    for (int i = currentPosition+1; i < pageNum; i ++) {
        if (strList[i] == currentPage) {
            return i;
        }
    }
    
    return 100;
}

//最佳置換算法
void replacePageByOPT(int memoryList[],int phyNum,int strList[],int pageNum){
    
    //置換次數
    int replaceCount = 0;
    //缺頁次數
    int missingCount = 0;
    
    //記錄在內存的物理塊的下一次訪問位置
    int nextPosition[phyNum];
    //初始化
    initializeList(nextPosition, phyNum);
    
    //記錄當前頁面的訪問情況: 0 未訪問
    int isVisited;
    
    for (int i = 0; i < pageNum; i ++) {
        isVisited = 0;
        //判斷是否需要置換->內存已滿且需要訪問的頁面不在內存中
        for (int j = 0; j < phyNum; j ++) {
            if (memoryList[j] == strList[i]) {
                //該頁面已經存在內存中
                //記錄下一次訪問它的位置
                nextPosition[j] = getNextPosition(memoryList[j], i, strList, pageNum);
                
                //修改訪問情況
                isVisited = 1;
                
                //展示
                printf("%d\n",strList[i]);
                break;
            }
            if (memoryList[j] == -1) {
                //頁面不在內存中且內存未滿->直接存入
                memoryList[j] = strList[i];
                nextPosition[j] = getNextPosition(memoryList[j], i, strList, pageNum);
                
                missingCount ++;
                
                //修改訪問情況
                isVisited = 1;
                
                //展示
                printf("%d\n",strList[i]);
                showMemoryList(memoryList, phyNum);
                break;
            }
        }
        
        if (!isVisited) {
            
            //當前頁面還沒訪問過
            //內存已滿且當前訪問不在內存中->進行置換
            //1.尋找到最晚才被訪問到的頁面
            int max = 0;
            for (int k = 1; k < phyNum; k ++) {
                if (nextPosition[max] < nextPosition[k]) {
                    max = k;
                }
            }
            
            
            //2.將該位置的頁面換出
            memoryList[max] = strList[i];
            nextPosition[max] = getNextPosition(memoryList[max], i, strList, pageNum);
            
            missingCount ++;
            replaceCount ++;
            
            //展示
            printf("%d\n",strList[i]);
            showMemoryList(memoryList, phyNum);
        }
    }
    informationCount(missingCount, replaceCount,pageNum);
}
//先進先出置換算法
void replacePageByFIFO(int memoryList[],int phyNum,int strList[],int pageNum){
    
    //置換次數
    int replaceCount = 0;
    //缺頁次數
    int missingCount = 0;
    
    //記錄當前最早進入內存的下標
    int pointer = 0;
    
    //記錄當前頁面的訪問情況: 0 未訪問
    int isVisited = 0;
    for (int i = 0; i < pageNum; i ++) {
        isVisited = 0;
        
        //判斷是否需要置換->內存已滿且需要訪問的頁面不在內存中
        for (int j = 0; j < phyNum; j ++) {
            if (memoryList[j] == strList[i]) {
                //該頁面已經存在內存中
                //修改訪問情況
                isVisited = 1;
                //修改訪問時間
                //展示
                printf("%d\n",strList[i]);
                break;
            }
            if (memoryList[j] == -1) {
                //頁面不在內存中且內存未滿->直接存入
                memoryList[j] = strList[i];
                //修改訪問情況
                isVisited = 1;
                missingCount ++;
                //展示
                printf("%d\n",strList[i]);
                showMemoryList(memoryList, phyNum);
                break;
            }
        }
        
        if (!isVisited) {
            //當前頁面還未被訪問過->需要進行頁面置換
            //直接把這個頁面存到所記錄的下標中
            memoryList[pointer] = strList[i];
            
            //下標指向下一個
            pointer ++;
            
            //如果到了最後一個,將下標歸零
            if (pointer > phyNum-1) {
                pointer = 0;
            }
            
            
            missingCount ++;
            replaceCount ++;
            
            //展示
            printf("%d\n",strList[i]);
            showMemoryList(memoryList, phyNum);
        }
    }
    informationCount(missingCount, replaceCount, pageNum);
}

//最近最久未使用置換算法
void replacePageByLRU(int memoryList[],int phyNum,int strList[],int pageNum){
    
    //置換次數
    int replaceCount = 0;
    //缺頁次數
    int missingCount = 0;

    //記錄內存中最近一次訪問至今的時間
    int timeRecord[phyNum];
    //初始化
    initializeList(timeRecord, phyNum);

    //記錄當前頁面的訪問情況: 0 未訪問
    int isVisited = 0;
    
    //記錄已經在內存中的頁面數量
    int pageCount = 0;
    for (int i = 0; i < pageNum; i ++) {
        isVisited = 0;
        
        //時間加一
        for (int p = 0; p < pageCount; p ++) {
            if (memoryList[p] != -1) {
                timeRecord[p] ++;
            }
        }
        
        //是否需要置換
        for (int j = 0; j < phyNum; j ++) {
            if (memoryList[j] != -1) {
                timeRecord[j] ++;
            }
            if (memoryList[j] == strList[i]) {
                //該頁面已經存在內存中
                //修改訪問情況
                isVisited = 1;
                //重置訪問時間
                timeRecord[j] = -1;
                //展示
                printf("%d\n",strList[i]);
                break;
            }
            if (memoryList[j] == -1) {
                //頁面不在內存中且內存未滿->直接存入
                memoryList[j] = strList[i];
                pageCount ++;
                //修改訪問情況
                isVisited = 1;
                //修改訪問時間
                timeRecord[j] ++;
                
                missingCount ++;
                //展示
                printf("%d\n",strList[i]);
                showMemoryList(memoryList, phyNum);
                break;
            }
        }

        if (!isVisited) {
            //需要置換
            //1.遍歷時間記錄表,尋找最久未訪問的頁面所在的內存下標
            int max = 0;
            for (int k = 0; k < phyNum; k ++) {
                if (timeRecord[max] < timeRecord[k]) {
                    max = k;
                }
            }

            //2.將該位置的頁面換出
            memoryList[max] = strList[i];
            timeRecord[max] = -1;
            
            missingCount ++;
            replaceCount ++;

            //展示
            printf("%d\n",strList[i]);
            showMemoryList(memoryList, phyNum);
            
        }
    }
    informationCount(missingCount, replaceCount, pageNum);
}

//最近最久未使用置換算法-2
//void replacePageByLRU(int memoryList[],int phyNum,int strList[],int pageNum){
//
//    int isVisited = 0;
//
//    //記錄已經在內存中的頁面數量
//    int pageCount = 0;
//    for (int i = 0; i < pageNum; i ++) {
//        isVisited = 0;
//        //判斷內存是否需要換頁
//        for (int j = 0; j < phyNum; j ++) {
//            if (memoryList[j] == strList[i]) {
//                //已經存在於內存中,把它換到隊列尾部
//                int temp = memoryList[j];
//                for (int k = j; k < pageCount-1; k ++) {
//                    memoryList[k] = memoryList[k+1];
//                }
//                memoryList[pageCount-1] = temp;
//
//                //修改訪問情況
//                isVisited = 1;
//                //修改訪問時間
//                //展示
//                printf("%d\n",strList[i]);
//                break;
//            }
//
//            if (memoryList[j] == -1) {
//                //頁面不在內存中且內存未滿->直接存入
//                memoryList[j] = strList[i];
//                //修改訪問情況
//                isVisited = 1;
//
//                pageCount ++;
//
//                //展示
//                printf("%d\n",strList[i]);
//                showMemoryList(memoryList, phyNum);
//                break;
//            }
//        }
//
//        if (!isVisited) {
//            //需要換頁
//            //1.直接將數組整體往前移一位
//            for (int k = 0; k < phyNum; k ++) {
//                memoryList[k] = memoryList[k+1];
//            }
//            //2.將當前頁面加到隊尾
//            memoryList[phyNum-1] = strList[i];
//            //展示
//            printf("%d\n",strList[i]);
//            showMemoryList(memoryList, phyNum);
//        }
//
//
//    }
//}
int main(int argc, const char * argv[]) {
    
    //物理塊的數量
    int phyBlockNum;
    printf("請輸入物理塊數量:\n");
    scanf("%d",&phyBlockNum);
    
    //生成內存隊列
    int memoryList[phyBlockNum];
    //初始化內存狀態
    initializeList(memoryList, phyBlockNum);
    //showMemoryList(memoryList,phyBlockNum);
    
    //頁面數量
    int pageNum;
    printf("請輸入要訪問的頁面總數:\n");
    scanf("%d",&pageNum);
    
    //保存頁面號引用串
    int pageNumStrList[pageNum];
    printf("請輸入要訪問的頁面號:\n");
    for (int i = 0; i < pageNum; i ++) {
        scanf("%d",&pageNumStrList[i]);
    }
    showList(pageNumStrList, pageNum);
    
    int chose;
    while (1) {
        printf("請選擇所需的置換算法:\n");
        printf("1.OPT 2.FIFO 3.LRU 4.退出\n");
        scanf("%d",&chose);
        
        switch (chose) {
            case 1:
                showList(pageNumStrList, pageNum);
                replacePageByOPT(memoryList, phyBlockNum, pageNumStrList, pageNum);
                //重新初始化內存
                initializeList(memoryList, phyBlockNum);
                break;
            case 2:
                showList(pageNumStrList, pageNum);
                replacePageByFIFO(memoryList, phyBlockNum, pageNumStrList, pageNum);
                //重新初始化內存
                initializeList(memoryList , phyBlockNum);
                break;
            case 3:
                showList(pageNumStrList, pageNum);
                replacePageByLRU(memoryList, phyBlockNum, pageNumStrList, pageNum);
                //重新初始化內存
                initializeList(memoryList, phyBlockNum);
                break;
            default:
                return 0;
                break;
        }
    }
    
    return 0;
}

實驗截圖

img_7
img_8
img_9

發佈了36 篇原創文章 · 獲贊 18 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章