TIT 操作系统实验一 三种页面置换算法(Optimal、FIFO、LRU)

该博客详细介绍了操作系统中页面置换算法的编程实现,包括最佳置换、先进先出和最近最久未使用算法。通过对不同算法的模拟,分析了它们在不同场景下的性能,特别是针对最佳置换算法存在的问题进行了修正,强调了算法在内存管理和性能优化中的关键作用。
摘要由CSDN通过智能技术生成

操作系统的三种页面置换算法

原创作者:原创,在原创作者的基础上进行了改进,(最佳置换,原作者第十行应该是ProcessBlocks[flag][j] 第62行j参数取值不对 第64行temp参数错误),三种算法均已实现

实验目的

编程模拟实现存储器页面置换的常用算法,调试分析相关存储器管理程序,加深对存储器页面置换常用算法的理解和实现技巧

实验内容

1、 自定义存储器管理有关的数据结构;

2、 依据最佳置换算法(Optimal)、先进先出置换算法(FIFO)、最近最久未使用算法(LRU)原理,编写对应函数,模拟系统的存储器页面置换功能;

3、 为了更好地模拟和评价算法的性能,允许用户自行指定可用页块数并输入需访问的页面号序列;

4、 统计以上算法实际需要的总页面数、缺页中断次数以及它们的缺页率;

5、 比较/分析以上算法的置换性能,并作出自己的评价

实验步骤

定义变量

public class 页面置换算法 {
    private static int MaxPage_num = 100;
    private static int[] PageView = new int[MaxPage_num];// 访问页面顺序
    private static int[][] Blocks = new int[MaxPage_num][MaxPage_num];// 物理块
    private static int[] PageCount = new int[MaxPage_num];// 记录权重

    private static int PageNum;// 访问页面个数
    private static int BlockNum;// 物理块个数

    //	private static int temp = 0;
    //	private static int flag = 0;
    private static int MissingPageNum;// 缺页个数
    private static double MissingPageRate;// 缺页率

    private static boolean found;// 判断是否找到

    private static int j;
    private static int i;
    private static int k;

    private static int NULL = -1;// 缺页

    // 动态输入物理块、页面、访问页面顺序
    public static void input() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入页面个数");
        PageNum = sc.nextInt();
        System.out.println("请输入物理块个数");
        BlockNum = sc.nextInt();
        System.out.println("请输入页面访问顺序");
        for (int i = 0; i < PageNum; i++) {
            PageView[i] = sc.nextInt();
        }
    }

输出函数

 // 输出结果
    public static void output() {
        // 输出访问页面
        System.out.print("访问页面:");
        for (i = 0; i < PageNum; i++) {
            System.out.print(PageView[i] + " ");
        }
        System.out.println();
        // 输出物理块
        System.out.println("物理块");
        for (int j = 0; j < BlockNum; j++) {
            for (int i = 0; i < PageNum; i++) {
                if (Blocks[i][j] == NULL)
                    System.out.print("  ");
                else
                    System.out.print(Blocks[i][j] + " ");
            }
            System.out.println(" ");
        }
        MissingPageRate = (double) MissingPageNum / PageNum;
        System.out.println();
        System.out.println("总页面数" + PageNum + "缺页次数" + MissingPageNum + "缺页率" + MissingPageRate + "%");
    }

初始化

    // 初始化物理块
    public static void original() {
        for (i = 0; i < PageNum; i++) {
            for (j = 0; j < BlockNum; j++) {
                Blocks[i][j] = NULL;
            }
        }
        MissingPageNum = 1;
    }

先进先出

 // 先进先出
    public static void FIFO() {
        original();

        Blocks[0][0] = PageView[0];
        int temp = 0, flag = 0;// temp标记本列,flag标记上一列
        for (i = 0; i < PageNum; i++) {
            // 如果页已进入物理块跳出循环
            for (j = 0; j < BlockNum; j++) {
                if (PageView[i] == Blocks[flag][j]) {
                    break;           
                }
            }

            //如果不存在
            if (j == BlockNum) {
                for (k = 0; k < BlockNum; k++) {
                    if (Blocks[flag][k] == NULL) {
                        break;
                    } else {
                        Blocks[i][k] = Blocks[flag][k];
                    }
                }
                temp++;
                temp = temp % BlockNum;
                Blocks[i][temp] = PageView[i];
                MissingPageNum++;
                flag = i;
            } else {
                continue;
            }
        }

        output();
    }

最佳置换

  // 最佳置换
    public static void OPT() {
        original();

        Blocks[0][0] = PageView[0];
        int temp, flag = 0;

        for (i = 0; i < PageNum; i++) {
            // 不缺页
            for (j = 0; j < BlockNum; j++) {
                if (PageView[i] == Blocks[flag][j]) {
                    break;
                }
            }
            if (j != BlockNum) { // 代表页面已经在内存块中不缺页
                continue;
            }
            // 缺页
            for (k = 0; k < BlockNum; k++) {
                if (Blocks[flag][k] == NULL) {
                    break;
                } else {
                    Blocks[i][k] = Blocks[flag][k];
                }
            }
            // 页面选择,满和不满
            // 缺页时物理块未满
            for (j = 0; j < BlockNum; j++) {
                if (Blocks[i][j] == NULL) {
                    Blocks[i][j] = PageView[i];
                    MissingPageNum++;
                    flag = i;
                    break;
                }
            }
            if (j != BlockNum) {
                continue;
            }

            // 缺页时内存块已满
            temp = 0;
            for (j = 0; j < BlockNum; j++) {
                // 向后遍历,寻找最久不访问
                for (k = i + 1; k < PageNum; k++) {
                    // 寻找最长时间内不被访问的页面 k是内存页面序列下标 存进PageCount数组内
                    if (Blocks[i][j] == PageView[k]) {
                        PageCount[j] = k;//找到,记录权重
                        break;
                    }
                }
            }

            // 剩下的页面没有和当前物理块一样的,把最后一块BlockNum物理块置换
            if (k == PageNum) {
                PageCount[j-1] = PageNum;
            }

            //			if (PageCount[temp] < PageCount[j]) {
            //				temp = j;
            				System.out.println("运行temp"+j);
            //			}

            for(int a=0;a<BlockNum;a++) {
                temp=temp>PageCount[a]?temp:a;
            }

            Blocks[i][temp] = PageView[i];
            MissingPageNum++;
            flag = i;
        }
        output();
    }

最近最久未使用


    // 最近最久未使用
    public static void LRU() {
        original();

        Blocks[0][0] = PageView[0];
        PageCount[0] = 0;
        int temp = 0, flag = 0;// temp标记本列,flag标记上一列
        for (i = 0; i < PageNum; i++) {
            // 不缺页
            for (j = 0; j < BlockNum; j++) {
                if (PageView[i] == Blocks[flag][j]) {
                    PageCount[j] = i;
                    break;
                }
            }
            if (j != BlockNum)
                continue;

            //缺页
            for (k = 0; k < BlockNum; k++) {
                if (Blocks[flag][k] == NULL) {
                    break;
                } else {
                    Blocks[i][k] = Blocks[flag][k];
                }
            }
            //缺页时物理块有空余
            for (j = 0; j < BlockNum; j++) {
                if (Blocks[i][j] == NULL) {
                    Blocks[i][j] = PageView[i];
                    PageCount[j] = i;
                    MissingPageNum++;
                    flag = i;
                    break;
                }
            }
            if (j != BlockNum) {
                continue;
            }
            //缺页时物理块没空余
            temp = 0;
            for (j = 0; j < BlockNum; j++) {
                if (PageCount[temp] > PageCount[j]) {
                    temp = j;
                }
            }
            Blocks[i][temp] = PageView[i];
            PageCount[temp] = i;
            MissingPageNum++;
            flag = i;


        }
        output();
    }

主函数

 public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        while (true) {
            input();
            System.out.println("1.先进先出 2.最佳置换算法 3.最近最久未使用 4.退出");
            int c = sc.nextInt();
            switch (c) {
                case 1:
                    FIFO();
                    break;
                case 2:
                    OPT();
                    break;
                case 3:
                    LRU();
                    break;
                case 4:
                    System.exit(0);
                default:
                    System.out.println("输入错误 重新输入");
                    break;
            }
        }
    }
}

完整代码

package 操作系统实验;

import java.util.Scanner;

public class 页面置换算法 {
    private static int MaxPage_num = 100;
    private static int[] PageView = new int[MaxPage_num];// 访问页面顺序
    private static int[][] Blocks = new int[MaxPage_num][MaxPage_num];// 物理块
    private static int[] PageCount = new int[MaxPage_num];// 记录权重

    private static int PageNum;// 访问页面个数
    private static int BlockNum;// 物理块个数

    //	private static int temp = 0;
    //	private static int flag = 0;
    private static int MissingPageNum;// 缺页个数
    private static double MissingPageRate;// 缺页率

    private static boolean found;// 判断是否找到

    private static int j;
    private static int i;
    private static int k;

    private static int NULL = -1;// 缺页

    // 动态输入物理块、页面、访问页面顺序
    public static void input() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入页面个数");
        PageNum = sc.nextInt();
        System.out.println("请输入物理块个数");
        BlockNum = sc.nextInt();
        System.out.println("请输入页面访问顺序");
        for (int i = 0; i < PageNum; i++) {
            PageView[i] = sc.nextInt();
        }
    }

    // 输出结果
    public static void output() {
        // 输出访问页面
        System.out.print("访问页面:");
        for (i = 0; i < PageNum; i++) {
            System.out.print(PageView[i] + " ");
        }
        System.out.println();
        // 输出物理块
        System.out.println("物理块");
        for (int j = 0; j < BlockNum; j++) {
            for (int i = 0; i < PageNum; i++) {
                if (Blocks[i][j] == NULL)
                    System.out.print("  ");
                else
                    System.out.print(Blocks[i][j] + " ");
            }
            System.out.println(" ");
        }
        MissingPageRate = (double) MissingPageNum / PageNum;
        System.out.println();
        System.out.println("总页面数" + PageNum + "缺页次数" + MissingPageNum + "缺页率" + MissingPageRate + "%");
    }

    // 初始化物理块
    public static void original() {
        for (i = 0; i < PageNum; i++) {
            for (j = 0; j < BlockNum; j++) {
                Blocks[i][j] = NULL;
            }
        }
        MissingPageNum = 1;
    }

    // 先进先出
    public static void FIFO() {
        original();

        Blocks[0][0] = PageView[0];
        int temp = 0, flag = 0;// temp标记本列,flag标记上一列
        for (i = 0; i < PageNum; i++) {
            // 如果页已进入物理块跳出循环
            for (j = 0; j < BlockNum; j++) {
                if (PageView[i] == Blocks[flag][j]) {
                    break;           
                }
            }

            //如果不存在
            if (j == BlockNum) {
                for (k = 0; k < BlockNum; k++) {
                    if (Blocks[flag][k] == NULL) {
                        break;
                    } else {
                        Blocks[i][k] = Blocks[flag][k];
                    }
                }
                temp++;
                temp = temp % BlockNum;
                Blocks[i][temp] = PageView[i];
                MissingPageNum++;
                flag = i;
            } else {
                continue;
            }
        }

        output();
    }

    // 最佳置换
    public static void OPT() {
        original();

        Blocks[0][0] = PageView[0];
        int temp, flag = 0;

        for (i = 0; i < PageNum; i++) {
            // 不缺页
            for (j = 0; j < BlockNum; j++) {
                if (PageView[i] == Blocks[flag][j]) {
                    break;
                }
            }
            if (j != BlockNum) { // 代表页面已经在内存块中不缺页
                continue;
            }
            // 缺页
            for (k = 0; k < BlockNum; k++) {
                if (Blocks[flag][k] == NULL) {
                    break;
                } else {
                    Blocks[i][k] = Blocks[flag][k];
                }
            }
            // 页面选择,满和不满
            // 缺页时物理块未满
            for (j = 0; j < BlockNum; j++) {
                if (Blocks[i][j] == NULL) {
                    Blocks[i][j] = PageView[i];
                    MissingPageNum++;
                    flag = i;
                    break;
                }
            }
            if (j != BlockNum) {
                continue;
            }

            // 缺页时内存块已满
            temp = 0;
            for (j = 0; j < BlockNum; j++) {
                // 向后遍历,寻找最久不访问
                for (k = i + 1; k < PageNum; k++) {
                    // 寻找最长时间内不被访问的页面 k是内存页面序列下标 存进PageCount数组内
                    if (Blocks[i][j] == PageView[k]) {
                        PageCount[j] = k;//找到,记录权重
                        break;
                    }
                }
            }

            // 剩下的页面没有和当前物理块一样的,把最后一块BlockNum物理块置换
            if (k == PageNum) {
                PageCount[j-1] = PageNum;
            }

            //			if (PageCount[temp] < PageCount[j]) {
            //				temp = j;
            //				System.out.println("运行temp"+j);
            //			}

            for(int a=0;a<BlockNum;a++) {
                temp=temp>PageCount[a]?temp:a;
            }

            Blocks[i][temp] = PageView[i];
            MissingPageNum++;
            flag = i;
        }
        output();
    }

    // 最近最久未使用
    public static void LRU() {
        original();

        Blocks[0][0] = PageView[0];
        PageCount[0] = 0;
        int temp = 0, flag = 0;// temp标记本列,flag标记上一列
        for (i = 0; i < PageNum; i++) {
            // 不缺页
            for (j = 0; j < BlockNum; j++) {
                if (PageView[i] == Blocks[flag][j]) {
                    PageCount[j] = i;
                    break;
                }
            }
            if (j != BlockNum)
                continue;

            //缺页
            for (k = 0; k < BlockNum; k++) {
                if (Blocks[flag][k] == NULL) {
                    break;
                } else {
                    Blocks[i][k] = Blocks[flag][k];
                }
            }
            //缺页时物理块有空余
            for (j = 0; j < BlockNum; j++) {
                if (Blocks[i][j] == NULL) {
                    Blocks[i][j] = PageView[i];
                    PageCount[j] = i;
                    MissingPageNum++;
                    flag = i;
                    break;
                }
            }
            if (j != BlockNum) {
                continue;
            }
            //缺页时物理块没空余
            temp = 0;
            for (j = 0; j < BlockNum; j++) {
                if (PageCount[temp] > PageCount[j]) {
                    temp = j;
                }
            }
            Blocks[i][temp] = PageView[i];
            PageCount[temp] = i;
            MissingPageNum++;
            flag = i;


        }
        output();
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        while (true) {
            input();
            System.out.println("1.先进先出 2.最佳置换算法 3.最近最久未使用 4.退出");
            int c = sc.nextInt();
            switch (c) {
                case 1:
                    FIFO();
                    break;
                case 2:
                    OPT();
                    break;
                case 3:
                    LRU();
                    break;
                case 4:
                    System.exit(0);
                default:
                    System.out.println("输入错误 重新输入");
                    break;
            }
        }
    }

}

运行结果

在这里插入图片描述
在这里插入图片描述

总结

通过页面置换算法程序的编写,最后三次相同物理块与访问次序输出比较,最佳置换算法选择以后永不使用的页面,以便保证最低的缺页率。先进先出算法在分配更多的物理块时反而会造成更高的缺页率。最近最久未使用算法,性能更好。


2021.12.1 对OPT修改

感谢达不溜的橘子评论,OPT运行结果错误。我找了好久问题,原码就不修改了,方便看过的人对比。
根据橘子的数据:答案应该为这样

70120304230321201701
777222227
00004000
1133311
实际为这样:
在这里插入图片描述
可以发现第一、二个物理块一直都没有被置换,说明对权重赋值有问题。

问题:
1.原代码63行,比较权重的逻辑不对。权重永远是最后一个物理块权重最大,因此总是最后一个被修改(修改后,若存在两个页面A、B都不再访问,那么权重都为最大,这里默认置换后者,可以在63行修改逻辑,使用随机数对A、B重新赋权,这里不赘述了,晚上两点了我想睡觉哇)。
2.原代码53行,把最后一个物理块置换这段代码,上面一段for执行最后一次外循环后,内循环没有找到,此时最后一个物理块权重也为最大。所以应在上一行for的外循环内。

	// 最佳置换
	public static void OPT() {
		original();

		Blocks[0][0] = PageView[0];
		int temp, flag = 0;

		for (i = 0; i < PageNum; i++) {
			// 不缺页
			for (j = 0; j < BlockNum; j++) {
				if (PageView[i] == Blocks[flag][j]) {
					break;
				}
			}
			if (j != BlockNum) { // 代表页面已经在内存块中不缺页
				continue;
			}
			// 缺页
			for (k = 0; k < BlockNum; k++) {
				if (Blocks[flag][k] == NULL) {
					break;
				} else {
					Blocks[i][k] = Blocks[flag][k];
				}
			}
			// 页面选择,满和不满
			// 缺页时物理块未满
			for (j = 0; j < BlockNum; j++) {
				if (Blocks[i][j] == NULL) {
					Blocks[i][j] = PageView[i];
					MissingPageNum++;
					flag = i;
					break;
				}
			}
			if (j != BlockNum) {
				continue;
			}

			// 缺页时内存块已满
			temp = 0;
			for (j = 0; j < BlockNum; j++) {
				// 向后遍历,寻找最久不访问
				for (k = i + 1; k < PageNum; k++) {
					// 寻找最长时间内不被访问的页面 k是内存页面序列下标 存进PageCount数组内
					if (Blocks[i][j] == PageView[k]) {
						PageCount[j] = k;//找到,记录权重
						break;
					}
				}
				// 剩下的页面没有和当前物理块一样的,将其权重设为最大值
				if (k == PageNum) {
					PageCount[j] = PageNum;
				}
			}

//			找出权重最大的块
			for(int a=1;a<BlockNum;a++) {
				if(PageCount[a]>PageCount[temp])
					temp=a;
			}

			Blocks[i][temp] = PageView[i];
			MissingPageNum++;
			flag = i;
		}
		output();
	}

测试结果:
在这里插入图片描述

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
好的,我可以为您解答这个问题。 首先,请求分页存储管理是指将一个进程所需的所有页面分为若干个固定大小的块,每个块称为一页,再将这些页调入内存中,以满足进程运行的需要。当内存中的页不足时,需要进行页面置换算法。 常用的页面置换算法OptimalFIFOLRU三种。 下面是这三种算法的简单实现: 1. Optimal算法 Optimal算法是一种理论上最优秀的页面置换算法,它选择在未来最长时间内不再被访问的页面进行置换。 实现思路: (1)对于每个内存块,预测它在未来的访问情况。 (2)选择未来最长时间内不再被访问的页面进行置换。 代码实现: ```python def optimal(pages, frames): page_faults = 0 page_frames = [None] * frames next_use = [0] * frames for i in range(len(pages)): if pages[i] not in page_frames: if None in page_frames: page_frames[page_frames.index(None)] = pages[i] else: farthest = max(j for j in range(len(page_frames)), key=lambda k: next_use[k]) page_frames[farthest] = pages[i] page_faults += 1 next_use[page_frames.index(pages[i])] = max(j for j in range(i, len(pages)) if pages[j] == pages[i]) if pages[i] in pages[i+1:] else len(pages) else: next_use[page_frames.index(pages[i])] = max(j for j in range(i, len(pages)) if pages[j] == pages[i]) if pages[i] in pages[i+1:] else len(pages) return page_faults ``` 2. FIFO算法 FIFO算法选择最先进入内存的页面进行置换。 实现思路: (1)使用一个队列来保存进入内存的页面,队首是最先进入的页面。 (2)当需要进行页面置换时,选择队首的页面进行置换。 代码实现: ```python def fifo(pages, frames): page_faults = 0 page_frames = [None] * frames queue = [] for i in range(len(pages)): if pages[i] not in page_frames: if None in page_frames: page_frames[page_frames.index(None)] = pages[i] queue.append(pages[i]) else: page_frames[page_frames.index(queue.pop(0))] = pages[i] queue.append(pages[i]) page_faults += 1 return page_faults ``` 3. LRU算法 LRU算法选择最近最少使用的页面进行置换。 实现思路: (1)使用一个列表来保存进入内存的页面,列表末尾是最近使用的页面。 (2)当需要进行页面置换时,选择列表头部的页面进行置换。 代码实现: ```python def lru(pages, frames): page_faults = 0 page_frames = [None] * frames for i in range(len(pages)): if pages[i] not in page_frames: if None in page_frames: page_frames[page_frames.index(None)] = pages[i] else: farthest = max(j for j in range(len(page_frames)), key=lambda k: pages[i-1::-1].index(page_frames[k]) if page_frames[k] in pages[i-1::-1] else -1) page_frames[farthest] = pages[i] page_faults += 1 return page_faults ``` 以上是OptimalFIFOLRU三种页面置换算法的简单实现。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值