前言
代碼有很多冗余,因為是寫作業時寫的,不過代碼簡單易懂,看看就可以改了。
置換算法介紹
頁面置換算法(也稱為頁面淘汰算法)是用來選擇換出頁面的算法。
在請求頁式存儲管理方式中,由於一個進程運行的時候不是所有的頁面都在內存中,所以會出現缺頁中斷。
當缺頁的時候內存沒有空閑的物理塊時就需要換出內存中的一頁,具體換出哪一頁面是由頁面置換算法決定的,頁面置換算法的優劣直接影響到系統的效率
要注意把頁面置換和連續分配方式中的交換區別開來,頁面置換的單位是頁面而不是整個進程,交換的單位是整個進程
當發生缺頁中斷后,系統不一定會執行頁面置換算法。因為發生缺頁中斷僅僅說明需要執行的頁面沒有在內存中,如果內存空間中還有空閑塊的話,只需要用缺頁中斷處理程序把需要的頁面從外存調入內存即可。不需要頁面置換算法:只有內存中沒有空閑塊的時候才需要頁面置換算法。
所以,缺頁中斷不一定導致執行頁面置換算法。
-
最佳置換算法(OPT)
在預知一個進程的頁面號引用串的情況下,每次都淘汰以后不再使用的或以后最遲再被使用的頁面,這種算法就是最佳置換算法
顯然,最佳置換算法是最優的,具有最低的缺頁率。但由於實際操作中往往無法事先知道以后會引用到所有頁面的信息,所以最佳置換算法無法實現,只能作為一個標准來衡量其他置換算法的優劣 -
先進先出算法(FIFO)
FIFO算法是最簡單的頁面置換算法,每次總是淘汰最先進入內存的頁面,也就是將在內存存駐留時間最長的頁面淘汰掉
該算法實現簡單,用一個隊列的數據結構就可以實現,將頁面按照次序排成一個隊列,並設置指針指向最先進入的頁面,每次需要淘汰頁面時,將指針所指的頁面淘汰即可,不過FIFO算法可能會產生Belady一場(缺頁次數隨着分配的物理塊號的增加而增加),而且由於FIFO算法與進程實際運行規律不符,可能會選擇淘汰程序經常使用的界面,實際效果不好 -
最近最少使用算法(LRU)
選擇最近最久沒有被使用的頁面予以淘汰,其思想是用以前的頁面引用情況來預測將來會出現頁面引用情況,也就是假設一個頁面剛被訪問,那么不久該頁面還會被訪問。即最佳置換算法是“向后看”,而“LRU”算法則是“向前看”
該算法可以用寄存器組和棧來實現,性能較好
關於算法中的judge
在考慮如何實現判斷那一個頁面被置換出時,原本是想通過一次次的遍歷來得到答案,但是這樣代碼顯得臃腫,於是我添加了一個和frame一樣長度的ArrayList:judge,
在 opt 算法中,judge中的數代表頁面在以后出現的位置,初始judge給的很大;
在 fifo 算法中,judge中的數代表頁面在物理塊中存在的時間,初始為0,越大代表存在的時間越長;
在 lru 算法中 judge 中的數代表沒被使用的時間,每訪問一個頁面將訪問時間設置為 1,沒被訪問的其他頁面則加1。
如此一來,三種算法都是將judge對應frame中最大的替換出去(就是說三種算法有冗余,還請各位自己修改修改^ - ^。
代碼
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
/*
* 中北大學
* 大數據學院
* 數據科學與大數據技術
* 19070542 1907040446
* */
public class Page_replace {
// 最佳置換算法
// opt 最佳頁面置換算法
static void opt(ArrayList<Integer> frame, ArrayList<Integer> page) {
System.out.println("============最佳頁面置換算法============");
// 框和頁面長度
int n_f = frame.size();
int n_p = page.size();
// 缺頁
int n_lack = n_f;
// 判斷塊:初始每個塊對應的頁面很大
ArrayList<Integer> judge = new ArrayList<Integer>(n_f);
for (int i = 0; i < n_f; i++) {
judge.add(99);
}
for (int i = 0; i < n_p; i++) {
System.out.print(page.get(i) + "===");
if (i < n_f) {
// 預裝入
frame.set(i, page.get(i));
System.out.println(frame);
} else {
if (frame.contains(page.get(i))) {
// 頁面已經存在在物理快中
System.out.println("頁面已經存在於物理塊");
} else {
// 更新往后頁面第一次出現的位置
for (int j = 0; j < 3; j++) {
int index = 99;
for (int k = i + 1; k < n_p; k++) {
if (frame.get(j) == page.get(k)) {
index = k;
break;
}
}
// 更新(
judge.set(j, index);
}
// 根據出現最后的(即judge對應最大的)替換
int index_max = judge.indexOf(Collections.max(judge));
int rep_page = frame.get(index_max);
frame.set(index_max, page.get(i));
System.out.print(frame);
System.out.println(" 替換掉了頁面:" + rep_page);
n_lack = n_lack + 1;
}
}
}
float p_lack = 100 * (float) n_lack / n_p;
System.out.println("===================================");
System.out.printf("缺頁次數:%d\n", n_lack);
System.out.printf("缺頁率: %.2f%%\n", p_lack);
System.out.println("===================================");
}
// fifo 先行先出算法
// fifo 先進先出置換算法
static void fifo(ArrayList<Integer> frame, ArrayList<Integer> page) {
System.out.println("============先進先出置換算法============");
// 框和頁面長度
int n_f = frame.size();
int n_p = page.size();
// 缺頁
int n_lack = n_f;
// 判斷塊:初始每個塊對應的出現次數
// 因為在預裝入之后才會有相應的判斷
// 使用我將判斷的狀態直接設置成預裝入之后 即為 3 2 1
ArrayList<Integer> judge = new ArrayList<Integer>(n_f);
for (int i = 0; i < n_f; i++) {
judge.add(3 - i);
}
for (int i = 0; i < n_p; i++) {
System.out.print(page.get(i) + "===");
if (i < n_f) {
// 預裝入
frame.set(i, page.get(i));
System.out.println(frame);
} else {
// 每個頁面存在次數加1
for (int j = 0; j < n_f; j++) {
judge.set(j, judge.get(j) + 1);
}
if (frame.contains(page.get(i))) {
// 頁面已經存在在物理塊中
System.out.println("頁面已經存在於物理塊");
} else {
// 根據存在最久的(即judge對應最大的)替換
int index_max = judge.indexOf(Collections.max(judge));
int rep_page = frame.get(index_max);
frame.set(index_max, page.get(i));
// 將新換進的存在狀態設置為1
judge.set(index_max, 1);
System.out.print(frame);
System.out.println(" 替換掉了頁面:" + rep_page);
n_lack = n_lack + 1;
}
}
}
float p_lack = 100 * (float) n_lack / n_p;
System.out.println("===================================");
System.out.printf("缺頁次數:%d\n", n_lack);
System.out.printf("缺頁率: %.2f%%\n", p_lack);
System.out.println("===================================");
}
// lru 最近最久未使用算法
static void lru(ArrayList<Integer> frame, ArrayList<Integer> page) {
System.out.println("===========最近最久未使用算法===========");
// 框和頁面長度
int n_f = frame.size();
int n_p = page.size();
// 缺頁
int n_lack = n_f;
// 和fifo類似先設置為 3 2 1
ArrayList<Integer> judge = new ArrayList<Integer>(n_f);
for (int i = 0; i < n_f; i++) {
judge.add(3 - i);
}
for (int i = 0; i < n_p; i++) {
System.out.print(page.get(i) + "===");
if (i < n_f) {
// 預裝入
frame.set(i, page.get(i));
System.out.println(frame);
} else {
// 每個頁面存在次數加1
for (int j = 0; j < n_f; j++) {
judge.set(j, judge.get(j) + 1);
}
if (frame.contains(page.get(i))) {
// 頁面已經存在在物理塊中
System.out.println("頁面已經存在於物理塊");
// 這一步fifo沒有
// 將頁面的使用重置為1
judge.set(frame.indexOf(page.get(i)), 1);
} else {
// 根據最久未使用的(即judge對應最大的)替換
int index_max = judge.indexOf(Collections.max(judge));
int rep_page = frame.get(index_max);
frame.set(index_max, page.get(i));
// 將新換進的使用狀態設置為1
judge.set(index_max, 1);
System.out.print(frame);
System.out.println(" 替換掉了頁面:" + rep_page);
n_lack = n_lack + 1;
}
}
}
float p_lack = 100 * (float) n_lack / n_p;
System.out.println("===================================");
System.out.printf("缺頁次數:%d\n", n_lack);
System.out.printf("缺頁率: %.2f%%\n", p_lack);
System.out.println("===================================");
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("請輸入分配給該作業的物理頁框塊數:");
int n_frame = scanner.nextInt(); // 物理頁框數
ArrayList<Integer> frame = new ArrayList<Integer>(n_frame);
for (int i = 0; i < n_frame; i++) {
frame.add(-1);
}
System.out.print("請輸入該作業的頁面走向:");
scanner.nextLine(); // 控制輸入格式
String inputPages = scanner.nextLine();
String[] split = inputPages.split("\\s+|,|,");
int n_page = split.length; // 作業的頁面走向總次數
ArrayList<Integer> page = new ArrayList<Integer>(n_page); // 作業的頁面走向
for (int i = 0; i < n_page; i++) {
page.add(Integer.parseInt(split[i]));
}
scanner.close();
// 測試輸入
// 3
// 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
opt(frame, page);
fifo(frame, page);
lru(frame, page);
}
}
結果




