LRU(Least Recently Used)最近未使用置換演算法--c實現

落悠發表於2021-01-19

在OS中,一些程式的大小超過記憶體的大小(比如好幾十G的遊戲要在16G的記憶體上跑),便產生了虛擬記憶體的概念

我們通過給每個程式適當的物理塊(記憶體),只讓經常被呼叫的頁面常駐在物理塊上,不常用的頁面就放在外存,等到要用的時候再從外存調入,從而實現虛擬記憶體

但是因為給的每個程式的物理塊大小不可能是無限的,如果該程式的物理塊用完了這時候又要調入新的頁面進來的話,就需要用到置換演算法,其中的一個演算法就叫

————>LRU(Least Recently Used)最近未使用置換演算法

一、程式碼思想

 

這個演算法的思想就是把已經很久沒用過的頁面,調出物理塊然後加入新的準備調入進來的頁面,對於每個物理塊有兩個元素

【頁面號丨此頁面至上次被訪問以來的時間t】

我用了二維陣列buffer[][2]來實現,buffer[i][0]表示的是在第i個物理塊裡的頁面號,buffer[i][1]示的是在第i個物理塊裡的頁面號已經有多久沒用被呼叫過了

二,全部程式碼

LRU(Least Recently Used)最近未使用置換演算法--c實現
 1 #include <iostream>
 2 using namespace std;
 3 
 4 int max(int arr[][2], int n)
 5 {
 6     int ans = 0;
 7     for (int i = 0; i < n; i++)
 8     {
 9         if (arr[i][1] > arr[ans][1])
10         {
11             ans = i;
12         }
13     }
14     return ans;
15 }
16 
17 void check(int buffer[][2],int n)
18 {
19     for (int i = 0; i < 3; i++)
20     {
21         cout << buffer[i][0] << ' ';
22     }
23     cout << endl << "--------" << endl;
24 }
25 
26 int exist_page_in_buffer(int buffer[][2], int page, int buffer_size)
27 {
28     for (int i = 0; i < buffer_size; i++)
29     {
30         if (buffer[i][0] == page)
31         {
32             return i;
33         }
34     }
35     return -1;
36 }
37 
38 void one_turn(int buffer[][2], int i)
39 {
40     for (int k = 0; k < i; k++)
41     {
42         buffer[k][1]++;
43     }
44 }
45 
46 void least_recently_used(int buffer[][2], int page[], int buffer_size, int page_size)
47 {
48     for (int i = 0; i < buffer_size; i++)//初始化buffer
49     {
50         buffer[i][0] = -1;
51         buffer[i][1] = 0;
52     }
53     for(int i = 0, j = 0; j < page_size;)//當頁面全部呼叫完成時(j >= page_size),演算法結束
54     {
55         //i是當前物理塊中已經有多少頁面了,j是已經有多少頁面進行過置換了
56         if (exist_page_in_buffer(buffer, page[j], i) != -1 )//當前的頁面page[j]已經存在於物理塊buffer之中
57         {
58             one_turn(buffer, i); //過了一個呼叫週期
59             buffer[exist_page_in_buffer(buffer, page[j], i)][1] = 0;//這個page又被呼叫一次,所以t為0
60             check(buffer, i);
61             j++;
62         }
63         else//當前的頁面page[j]不存在於物理塊buffer之中
64         {
65             if (i < buffer_size)//如果物理塊還沒有滿的話,直接加一個頁面進來,就不進行置換了
66             {
67                 buffer[i][0] = page[j];
68                 one_turn(buffer, i);
69                 check(buffer, i);
70                 i++; //當前物理塊中的頁面個數加一,因為buffer沒滿,加到滿為止
71                 j++;
72             }
73             else//物理塊已經滿了,進行LRU的查詢置換
74             {
75                 int temp = max(buffer, buffer_size);//找一個最久沒有被呼叫的頁面進行置換
76                 buffer[temp][0] = page[j];
77                 one_turn(buffer, buffer_size);
78                 buffer[temp][1] = 0;//這個page被置換進來呼叫一次,所以t為0
79                 check(buffer, i);
80                 j++;
81             }
82         }
83     }
84 }
85 
86 int main()
87 {
88     int page[] = { 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1 };
89     int buffer[3][2];
90     int n = sizeof(page)/sizeof(int);
91     least_recently_used(buffer, page, 3, 20);
92 }
View Code

 

三、程式碼解釋

首先主函式呼叫LRU演算法,函式least_recently_used進入函式棧,page的資料來源我會在下面給出例題

LRU(Least Recently Used)最近未使用置換演算法--c實現
1 int main()
2 {
3     int page[] = { 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1 };
4     int buffer[3][2];
5     int n = sizeof(page)/sizeof(int);
6     least_recently_used(buffer, page, 3, 20);
7 }
View Code

 

然後呼叫函式least_recently_used,首先進行對於buffer的初始化,然後進行迴圈呼叫頁面,當頁面全部呼叫完成時(j >= page_size),演算法結束

LRU(Least Recently Used)最近未使用置換演算法--c實現
 1 void least_recently_used(int buffer[][2], int page[], int buffer_size, int page_size)
 2 {
 3     for (int i = 0; i < buffer_size; i++)//初始化buffer
 4     {
 5         buffer[i][0] = -1;
 6         buffer[i][1] = 0;
 7     }
 8     for(int i = 0, j = 0; j < page_size;)//當頁面全部呼叫完成時(j >= page_size),演算法結束
 9     {
10         //i是當前物理塊中已經有多少頁面了,j是已經有多少頁面進行過置換了
11         if (exist_page_in_buffer(buffer, page[j], i) != -1 )//當前的頁面page[j]已經存在於物理塊buffer之中
12         {
13             one_turn(buffer, i); //過了一個呼叫週期
14             buffer[exist_page_in_buffer(buffer, page[j], i)][1] = 0;//這個page又被呼叫一次,所以t為0
15             check(buffer, i);
16             j++;
17         }
18         else//當前的頁面page[j]不存在於物理塊buffer之中
19         {
20             if (i < buffer_size)//如果物理塊還沒有滿的話,直接加一個頁面進來,就不進行置換了
21             {
22                 buffer[i][0] = page[j];
23                 one_turn(buffer, i);
24                 check(buffer, i);
25                 i++; //當前物理塊中的頁面個數加一,因為buffer沒滿,加到滿為止
26                 j++;
27             }
28             else//物理塊已經滿了,進行LRU的查詢置換
29             {
30                 int temp = max(buffer, buffer_size);//找一個最久沒有被呼叫的頁面進行置換
31                 buffer[temp][0] = page[j];
32                 one_turn(buffer, buffer_size);
33                 buffer[temp][1] = 0;//這個page被置換進來呼叫一次,所以t為0
34                 check(buffer, i);
35                 j++;
36             }
37         }
38     }
39 }
View Code

 

再解釋一下每個函式的作用

max,這個就是從buffer裡找到最久沒用呼叫過的頁面,返回他的所在物理塊的位置

LRU(Least Recently Used)最近未使用置換演算法--c實現
 1 int max(int arr[][2], int n)
 2 {
 3     int ans = 0;
 4     for (int i = 0; i < n; i++)
 5     {
 6         if (arr[i][1] > arr[ans][1])
 7         {
 8             ans = i;
 9         }
10     }
11     return ans;
12 }
View Code

 

check,檢查函式的執行情況

LRU(Least Recently Used)最近未使用置換演算法--c實現
1 void check(int buffer[][2],int n)
2 {
3     for (int i = 0; i < 3; i++)
4     {
5         cout << buffer[i][0] << ' ';
6     }
7     cout << endl << "--------" << endl;
8 }
View Code

 

exist_page_in_buffer,每次調入頁面時,都先檢查一遍這個頁面有沒有已經被調入到當前的物理塊中,如果在,返回此頁面在物理塊中的位置,如果不在,返回-1

LRU(Least Recently Used)最近未使用置換演算法--c實現
 1 int exist_page_in_buffer(int buffer[][2], int page, int buffer_size)
 2 {
 3     for (int i = 0; i < buffer_size; i++)
 4     {
 5         if (buffer[i][0] == page)
 6         {
 7             return i;
 8         }
 9     }
10     return -1;
11 }
View Code

 

one_turn,過了一個呼叫週期(主要就是為了讓其他的page距離上次被呼叫的時間t++)

LRU(Least Recently Used)最近未使用置換演算法--c實現
1 void one_turn(int buffer[][2], int i)
2 {
3     for (int k = 0; k < i; k++)
4     {
5         buffer[k][1]++;
6     }
7 }
View Code

 

四、書上例題和執行結果

 

 運算結果如下

7 -1 -1
--------
7 0 -1
--------
7 0 1
--------
2 0 1
--------
2 0 1
--------
2 0 3
--------
2 0 3
--------
4 0 3
--------
4 0 2
--------
4 3 2
--------
0 3 2
--------
0 3 2
--------
0 3 2
--------
1 3 2
--------
1 3 2
--------
1 0 2
--------
1 0 2
--------
1 0 7
--------
1 0 7
--------
1 0 7
--------

相關文章