【作業系統】頁面置換演算法(最佳置換演算法)(C語言實現)

月亮.?發表於2020-12-13

【作業系統】頁面置換演算法(最佳置換演算法)(C語言實現)

(編碼水平較菜,寫部落格也只是為了個人知識的總結和督促自己學習,如果有錯誤,希望可以指出)

1.頁面置換演算法:

在地址對映過程中,若在頁面中發現所要訪問的頁面不在記憶體中,則產生缺頁中斷。當發生缺頁中斷時,如果作業系統記憶體中沒有空閒頁面,則作業系統必須在記憶體選擇一個頁面將其移出記憶體,以便為即將調入的頁面讓出空間。而用來選擇淘汰哪一頁的規則叫做頁面置換演算法。

一個好的頁面置換演算法,應具有較低的頁面更換頻率。從理論上講,應該保留最近重複訪問的頁面,將以後都不再訪問或者很長時間內不再訪問的頁面調出。----百度百科

2.具體的頁面置換演算法:

2.1 最佳置換演算法:一個程式在記憶體的若干個頁面中,哪一個頁面是未來最長時間內不再被訪問的,那麼如果發生缺頁中斷時,就將該頁面換出,以便存放後面調入記憶體中的頁面。

在這裡插入圖片描述

1.這是計算機作業系統(第四版)中的一個例子。系統首先為程式分配了三個物理塊。上面一排數字是作業號。在轉滿三個物理塊後,要訪問2號作業,2號作業不在記憶體,所以會發生缺頁中斷,然後系統需要將2號作業調入記憶體,但是此時物理塊已經裝滿。
2.依據最佳置換演算法,會將7號頁換出(0號頁在2號頁後第1個就會被訪問,1號頁在2號頁後第10個會被訪問,7號頁在2號頁後第14個會被訪問,7號頁在已經裝入記憶體的作業中是未來最長時間不會被訪問的,所以換出7號頁)。
3.後面依次類推。

2.2 先進先出演算法:如果發生缺頁中斷,需要換出一個頁面的時候,總是選擇最早進入記憶體的頁面,即選擇在記憶體中駐留時間最久的頁面進行換出。

在這裡插入圖片描述
有點不清楚。。。。。就是每次發生缺頁就將最早進入記憶體的頁面換出,然後將剛調入的頁面換入該物理塊。

2.3 最近最久未使用(LRU)置換演算法:LRU演算法是缺頁中斷髮生時選擇最久未使用的頁面進行換出。

在這裡插入圖片描述
這個演算法其實也很好判斷。分享一個小技巧。記憶體分配了k個物理塊,發生缺頁中斷將要往記憶體調入某個頁面的時候,在該頁面往前面數K個物理塊最前面的那個就會是要換出的,因為該頁面最長時間未被使用過。(可能前面會有重複的頁面,有幾個重複的頁面就再往前面多數幾個)
例如:裝入7,0,1,之後訪問2號頁面的時候會發生缺頁中斷。此時物理塊有三個,2號頁面前面有三個頁面,最前面的是7號頁面所以將7號頁面換出。

2.4Clock置換演算法(沒有動圖,不太形象,就不舉例子了,如果不太清楚,可以私信我。)

2.4.1簡單的Clock置換演算法:將所有頁面通過連結指標連線成一個迴圈佇列。然後需要為每一個頁面設定一個訪問位。當某頁被訪問的時候,將訪問位置為1。選擇頁面換出的時候,需要檢查頁面的訪問位。如果是0,就將頁面換出,如果是1,那麼就將訪問位置為0。

簡單的Clock演算法最多訪問兩輪:
最壞情況就是所有的頁面訪問位都是1,訪問1輪之後,全部訪問位都會被置為0,那麼肯定會找到一個頁面換出。

2.42改進型Clock演算法:將所有頁面通過連結指標連線成一個迴圈佇列。然後需要為每一個頁面設定一個訪問位和一個修改位。訪問位為0表示未訪問過,為1表示訪問過。修改位為0表示未修改過,為1表示修改過。

此時頁面會有四種情況:
1.未被訪問,未被修改,最佳淘汰。
2.未被訪問,被修改過。
3.被訪問過,未被修改。
4.被訪問過,被修改過。

換出頁面的時候:

1.尋找未被訪問,未被修改的頁面,不修改訪問位。找到則換出,找不到進行第二步。
2.尋找未被訪問,但是被修改過的頁面。此時,每次掃描頁面的時候,將所有訪問位置為0。找到就返回,找不到就進行第三步。
3.重複第一次步驟,尋找未被訪問,未被修改的頁面,不修改訪問位。找到則換出,找不到進行第四步。
4.重複第二步。尋找未被訪問,但是被修改過的頁面。此時一定可以找到。

也就是說,改進型Clock演算法,最多掃描四輪佇列。因為最壞的情況就是全部頁面的訪問位和修改位都是1的情況。在經過第二輪掃描之後頁面的訪問位已經都是0。所以第四輪一定可以找到一個頁面換出。

3.最佳置換演算法執行截圖:

首先是前面三個裝入,就省略掉了直接從第四次之後開始列印的。
在這裡插入圖片描述

4.程式碼

#include<stdio.h>
#include<stdlib.h>

#define MAX 20   // 定義作業序列的最大長度
#define num_alloacte 3       //記憶體分配給程式的物理塊數  , 也就是同一時刻最多有幾個頁面可以在記憶體中

int work_list [MAX];        //儲存作業序列
int num;        //儲存要輸入的序列的長度

int memory_alloacte [num_alloacte];   // 現在在程式中的頁面序列

int current; // 記錄已經分配的作業的下標

void input(){       //初始化作業序列  , 以及記憶體分配給程式的物理塊數
    printf("請輸入作業的個數:");
    scanf("%d",&num);
    if (num > MAX)  {
        printf("序列過長");
        return;    
    }
    printf("請輸入作業序列:\n");
    for(int i = 0;i < num; i ++){
        scanf("%d",&work_list[i]);
    }
    for(int i = 0;i < MAX ; i ++){
        memory_alloacte[i] = -1;
    }
    for(int i = 0;i < num_alloacte;i ++){
        memory_alloacte[i] = work_list[i];
        current = i;
    }
}

void print(int* work_list,int* memory_alloacte ){
    printf("\t現在程式中的頁面序列:");
    for(int i = 0; i < num_alloacte; i ++){
        printf("%3d\t",*(memory_alloacte+i));
    }
    printf("\t\t當前剩餘的作業序列:");
    for(int i = current+1; i < num;i ++){
        printf("%3d",*(work_list+i));
    }
    printf("\n");
}

int judge(){
    int temp [num_alloacte];            //賦值一個臨時變數 記錄此時物理框中的作業號
    int count = num_alloacte;           //記錄臨時變數物理框中還剩下的個數
    for(int i = 0;i < num_alloacte; i ++){
        temp[i] = memory_alloacte[i];   
    }   
    int cur = current + 1;
    while (cur < num)
    {
       for (int i = 0; i < num_alloacte; i++)
       {
           if(work_list[cur] == temp[i]){       //如果剩下的工作序列中 現有記憶體中的作業還會呼叫的話, 就將其的值置為  -1    
               if(count == 1){              //此時記憶體中剩下的那個作業號肯定是最長時間沒有呼叫過的,後者是以後再也不會呼叫
                   return i;
               }
               temp[i] = -1;
               count --;
               break;
           }
       }
       cur ++;
    }
    //此時再來遍歷這個 臨時的物理塊中作業號的  陣列  ,  如果他的值不是  -1,就說明後面需要呼叫的作業中再也沒有這個作業了,所以 就可以直接返回。  
    for(int i = 0;i < num_alloacte;i ++){
        if(temp[i] != -1){
            return i;
        }
        else
        {
            continue;
        }
        
    }
    return 0;
}

void change(){
    int index;
    int flag = 0;
    for (int i = current + 1; i < num; i++)
    {   
    
        for (int j = 0; j < num_alloacte; j++)          //來判斷下一個作業是否已經在記憶體中
        {
            if(work_list[i] == memory_alloacte[j]){
                flag = 1;                       //是的話讓標誌位置為1
                break;
            }
        }
        if(flag == 0){                          //說明不在記憶體中,會出現頁面中斷。需要進行換頁。
            index = judge();
            if(memory_alloacte[index] != work_list[i]){
                memory_alloacte[index] = work_list[i];
            }
            current ++;
            print(work_list,memory_alloacte);
            
        }
        else
        {
            flag = 0;
            current ++;
            print(work_list,memory_alloacte);
            continue;
        }
        
    }
}
int main(){

    input();

    change();

    system("pause");
}

相關文章