操作系统: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);
	}
}

结果

java页面置换算法 页面置换算法代码java_缺页


java页面置换算法 页面置换算法代码java_缺页_02


java页面置换算法 页面置换算法代码java_页面置换_03


java页面置换算法 页面置换算法代码java_页面置换算法代码java_04