操作系統:Java實現頁面置換算法(OPT,FIFO,LRU)


前言

  代碼有很多冗余,因為是寫作業時寫的,不過代碼簡單易懂,看看就可以改了。

置換算法介紹

  頁面置換算法(也稱為頁面淘汰算法)是用來選擇換出頁面的算法。
  在請求頁式存儲管理方式中,由於一個進程運行的時候不是所有的頁面都在內存中,所以會出現缺頁中斷。
  當缺頁的時候內存沒有空閑的物理塊時就需要換出內存中的一頁,具體換出哪一頁面是由頁面置換算法決定的,頁面置換算法的優劣直接影響到系統的效率

  要注意把頁面置換和連續分配方式中的交換區別開來,頁面置換的單位是頁面而不是整個進程,交換的單位是整個進程
  當發生缺頁中斷后,系統不一定會執行頁面置換算法。因為發生缺頁中斷僅僅說明需要執行的頁面沒有在內存中,如果內存空間中還有空閑塊的話,只需要用缺頁中斷處理程序把需要的頁面從外存調入內存即可。不需要頁面置換算法:只有內存中沒有空閑塊的時候才需要頁面置換算法。
  所以,缺頁中斷不一定導致執行頁面置換算法。

  1. 最佳置換算法(OPT)
        在預知一個進程的頁面號引用串的情況下,每次都淘汰以后不再使用的或以后最遲再被使用的頁面,這種算法就是最佳置換算法
        顯然,最佳置換算法是最優的,具有最低的缺頁率。但由於實際操作中往往無法事先知道以后會引用到所有頁面的信息,所以最佳置換算法無法實現,只能作為一個標准來衡量其他置換算法的優劣

  2. 先進先出算法(FIFO)
        FIFO算法是最簡單的頁面置換算法,每次總是淘汰最先進入內存的頁面,也就是將在內存存駐留時間最長的頁面淘汰掉
        該算法實現簡單,用一個隊列的數據結構就可以實現,將頁面按照次序排成一個隊列,並設置指針指向最先進入的頁面,每次需要淘汰頁面時,將指針所指的頁面淘汰即可,不過FIFO算法可能會產生Belady一場(缺頁次數隨着分配的物理塊號的增加而增加),而且由於FIFO算法與進程實際運行規律不符,可能會選擇淘汰程序經常使用的界面,實際效果不好

  3. 最近最少使用算法(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);
	}
}

結果





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM