在OS中,一些程式的大小超過記憶體的大小(比如好幾十G的遊戲要在16G的記憶體上跑),便產生了虛擬記憶體的概念
我們通過給每個程式適當的物理塊(記憶體),只讓經常被呼叫的頁面常駐在物理塊上,不常用的頁面就放在外存,等到要用的時候再從外存調入,從而實現虛擬記憶體
但是因為給的每個程式的物理塊大小不可能是無限的,如果該程式的物理塊用完了這時候又要調入新的頁面進來的話,就需要用到置換演算法,其中的一個演算法就叫
————>LRU(Least Recently Used)最近未使用置換演算法
一、程式碼思想
這個演算法的思想就是把已經很久沒用過的頁面,調出物理塊然後加入新的準備調入進來的頁面,對於每個物理塊有兩個元素
【頁面號丨此頁面至上次被訪問以來的時間t】
我用了二維陣列buffer[][2]來實現,buffer[i][0]表示的是在第i個物理塊裡的頁面號,buffer[i][1]示的是在第i個物理塊裡的頁面號已經有多久沒用被呼叫過了
二,全部程式碼
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 }
三、程式碼解釋
首先主函式呼叫LRU演算法,函式least_recently_used進入函式棧,page的資料來源我會在下面給出例題
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 }
然後呼叫函式least_recently_used,首先進行對於buffer的初始化,然後進行迴圈呼叫頁面,當頁面全部呼叫完成時(j >= page_size),演算法結束
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 }
再解釋一下每個函式的作用
max,這個就是從buffer裡找到最久沒用呼叫過的頁面,返回他的所在物理塊的位置
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 }
check,檢查函式的執行情況
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 }
exist_page_in_buffer,每次調入頁面時,都先檢查一遍這個頁面有沒有已經被調入到當前的物理塊中,如果在,返回此頁面在物理塊中的位置,如果不在,返回-1
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 }
one_turn,過了一個呼叫週期(主要就是為了讓其他的page距離上次被呼叫的時間t++)
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 }
四、書上例題和執行結果
運算結果如下
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
--------