操作系统|| 虚拟内存页置换算法

题目

写一个程序来实现 FIFO 和 LRU 页置换算法。首先,产生一个随机的页面引用序列,页面数从 0~9。将这个序列应用到每个算法并记录发生的页错误的次数。实现这个算法时要将页帧的数量设为可变。假设使用请求调页。可以参考所示的抽象类。

抽象类:

public abstract class ReplacementAlgorithm 
{ 
protected int pageFaultCount; // the number of page faults 
protected int pageFrameCount; // the number of physical page frame 
// pageFrameCount the number of physical page frames 
public ReplacementAlgorithm(int pageFrameCount) { 
if (pageFrameCount <0) 
throw new IllegalArgumentException(); 
this.pageFrameCount = pageFrameCount; 
pageFaultCount= 0; } 
// return - the number of page faults that occurred 
public int getPageFaultCount() { 
return pageFaultCount; 
} 
// int pageNumber - the page number to be inserted 
public abstract void insert (int pageNumber); 
} 


采用 LRU 页置换算法,另一个采用 FIFO 算法。
有两个类可以在线测试你的算法。
(1)PageGenerator——该类生成页面引用序列,页面数从 0~9。引用序列
的大小可作为 PageGenerateor 构造函数的参数。在创建 PageGenerator 对象后,
可用方法 getReferenceString0 方法返回作为引用序列的整数数组。
(2)Test-用来测试你的基于 ReplacementAlgorithm 的两个类 FIFO 与 LRU。
Test 可按如下方法调用:

Java Test <reference string #> <# of page frames> 

算法介绍

先进先出算法(FIFO):缺页中断发生时,系统选择在内存中驻留时间最长的页面淘汰。通常采用链表记录进入物理内存中的逻辑页面,链首时间最长。
该算法实现简单,但性能较差,调出的页面可能是经常访问的页面,而且进程分配物理页面数增加时,缺页并不一定减少(Belady 现象)。

优点 :实现简单,只需要维护一个先进先出队列,每次淘汰时直接操作队列头部即可。
缺点 :性能较差,因为被调出的页面可能是经常访问的页面。会发生 Belady 现象(颠簸现象),当进程分配的物理页面数增加时,缺页次数反而可能增加。

Java伪代码:

public class FIFO {private Queue<Integer> queue = new LinkedList<>();private Set<Integer> pageSet = new HashSet<>();private int capacity;public FIFO(int capacity) {this.capacity = capacity;}public void accessPage(int page) {if (pageSet.contains(page)) {// 页面已在内存中,不需要处理return;}if (pageSet.size() < capacity) {// 内存未满,将页面加入队列和集合queue.offer(page);pageSet.add(page);System.out.println("页面 " + page + " 调入内存");} else {// 内存已满,淘汰队首页面int evictPage = queue.poll();pageSet.remove(evictPage);System.out.println("页面 " + evictPage + " 被淘汰");// 将新页面加入队列和集合queue.offer(page);pageSet.add(page);System.out.println("页面 " + page + " 调入内存");}}public static void main(String[] args) {FIFO fifo = new FIFO(3);int[] pages = {1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5};for (int page : pages) {System.out.print("访问页面 " + page + ":");fifo.accessPage(page);System.out.println("当前内存中的页面:" + fifo.pageSet);System.out.println();}}
}


最近最久未使用算法(LRU):算法思想是缺页发生时,选择最长时间没有被引用的页面进行置换,如某些页面长时间未被访问,则它们在将来还可能会长时间不会访问。该算法的开销较大。

优点 :具有较好的性能,能够较好地预测页面的使用频率。
缺点 :实现相对复杂,需要记录每个页面的访问时间,并且每次访问都需要更新访问时间。

Java伪代码:

public class LRU {private Map<Integer, Integer> pageMap = new HashMap<>();private List<Integer> pageList = new ArrayList<>();private int capacity;public LRU(int capacity) {this.capacity = capacity;}public void accessPage(int page) {if (pageMap.containsKey(page)) {// 页面已在内存中,更新其位置pageList.remove(Integer.valueOf(page));pageList.add(page);System.out.println("页面 " + page + " 已在内存中,更新其位置");} else {if (pageList.size() < capacity) {// 内存未满,将页面加入列表和映射pageList.add(page);pageMap.put(page, pageList.size() - 1);System.out.println("页面 " + page + " 调入内存");} else {// 内存已满,淘汰最久未使用的页面(列表开头的页面)int evictPage = pageList.remove(0);pageMap.remove(evictPage);System.out.println("页面 " + evictPage + " 被淘汰");// 将新页面加入列表和映射pageList.add(page);pageMap.put(page, pageList.size() - 1);System.out.println("页面 " + page + " 调入内存");}}}public static void main(String[] args) {LRU lru = new LRU(3);int[] pages = {1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5};for (int page : pages) {System.out.print("访问页面 " + page + ":");lru.accessPage(page);System.out.println("当前内存中的页面:" + lru.pageList);System.out.println();}}
}

关键步骤

 (1)在PageGenerator类中,构造函数PageGenerator(int count)中生成随机的页面引用序列。

public PageGenerator(int count) {if (count < 0)throw new IllegalArgumentException();java.util.Random generator = new java.util.Random();referenceString = new int[count];for (int i = 0; i < count; i++)referenceString[i] = generator.nextInt(RANGE + 1);
}

(2)在ReplacementAlgorithm抽象类的子类FIFO和LRU中,实现页面置换算法。
FIFO类:实现FIFO算法(First-In, First-Out):将最早插入的页面替换出去。

@Override
public void insert(int pageNumber) {boolean pageFault = true;// 检查页面是否已经在物理页面帧中for (int i = 0; i < pageFrameCount; i++) {if (pageFrames[i] == pageNumber) {pageFault = false;break;}}// 如果页面不在物理页面帧中,则发生页面错误if (pageFault) {pageFaultCount++;pageFrames[currentIndex] = pageNumber;currentIndex = (currentIndex + 1) % pageFrameCount;}
}

LRU类:实现LRU算法(Least Recently Used):将最长时间未被使用的页面替换出去

@Override
public void insert(int pageNumber) {boolean pageFault = true;int oldestTimestampIndex = 0;int oldestTimestamp = timestamps[0];// 检查页面是否已经在物理页面帧中for (int i = 0; i < pageFrameCount; i++) {if (pageFrames[i] == pageNumber) {pageFault = false;// 更新页面的时间戳timestamps[i] = getCurrentTimestamp();break;}// 找到最老的时间戳和对应的页面帧索引if (timestamps[i] < oldestTimestamp) {oldestTimestamp = timestamps[i];oldestTimestampIndex = i;}}// 如果页面不在物理页面帧中,则发生页面错误if (pageFault) {pageFaultCount++;pageFrames[oldestTimestampIndex] = pageNumber;timestamps[oldestTimestampIndex] = getCurrentTimestamp();}
}

(3)在Test类中,使用FIFO和LRU算法计算页面错误次数。

PageGenerator ref = new PageGenerator(new Integer(args[0]).intValue());int[] referenceString = ref.getReferenceString();/** Use either the FIFO or LRU algorithms */
ReplacementAlgorithm fifo = new FIFO(new Integer(args[1]).intValue());
ReplacementAlgorithm lru = new LRU(new Integer(args[1]).intValue());// 插入页面时输出消息
for (int i = 0; i < referenceString.length; i++) {// System.out.println("inserting " + referenceString[i]);lru.insert(referenceString[i]);
}// 插入页面时输出消息
for (int i = 0; i < referenceString.length; i++) {// System.out.println("inserting " + referenceString[i]);fifo.insert(referenceString[i]);
}// 报告页面错误总数
System.out.println("LRU faults = " + lru.getPageFaultCount());
System.out.println("FIFO faults = " + fifo.getPageFaultCount());

源码


/*** This class generates page references ranging from 0 .. 9** Usage:*	PageGenerator gen = new PageGenerator()*	int[] ref = gen.getReferenceString();*/public class PageGenerator
{private static final int DEFAULT_SIZE = 100;private static final int RANGE = 9;int[] referenceString;public PageGenerator() {this(DEFAULT_SIZE);}public PageGenerator(int count) {if (count < 0)throw new IllegalArgumentException();java.util.Random generator = new java.util.Random();referenceString = new int[count];for (int i = 0; i < count; i++)referenceString[i] = generator.nextInt(RANGE + 1);}public int[] getReferenceString() {/*** comment out the following two lines to* generate random reference strings*/int[] str = {7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1};//int[] str = {1,2,3,4,1,2,5,1,2,3,4,5};return str;/*** and uncomment the following line*/	//return referenceString;}
}
/*** ReplacementAlgorithm.java **/public abstract class ReplacementAlgorithm
{// the number of page faultsprotected int pageFaultCount;// the number of physical page frameprotected int pageFrameCount;/*** @param pageFrameCount - the number of physical page frames*/public ReplacementAlgorithm(int pageFrameCount) {if (pageFrameCount < 0)throw new IllegalArgumentException();this.pageFrameCount = pageFrameCount;pageFaultCount = 0;}/*** @return - the number of page faults that occurred.*/public int getPageFaultCount() {return pageFaultCount;}/*** @param pageNumber - the page number to be inserted*/public abstract void insert(int pageNumber); 
}
public class FIFO extends ReplacementAlgorithm{private int[] pageFrames;private int currentIndex;public FIFO(int pageFrameCount){super(pageFrameCount);pageFrames = new int[pageFrameCount];currentIndex = 0;}@Overridepublic void insert(int pageNumber) {boolean pageFault = true;//check pages whether in pageFramesfor(int i =0;i<pageFrameCount;i++){if(pageFrames[i]==pageNumber){pageFault = false;break;}}//if pages not in pagesFrames,it happens faultsif(pageFault){pageFaultCount++;pageFrames[currentIndex] = pageNumber;currentIndex = (currentIndex+1)%pageFrameCount;}}
}
public class LRU extends ReplacementAlgorithm{private int[] pageFrames;private int[] timestamps;/*** @param pageFrameCount - the number of physical page frames*/public LRU(int pageFrameCount) {super(pageFrameCount);pageFrames = new int[pageFrameCount];timestamps = new int[pageFrameCount];}@Overridepublic void insert(int pageNumber) {boolean pageFault = true;int oldestTimestampIndex = 0;int oldestTimestamp = timestamps[0];//check pages whether in pagesFramesfor(int i =0;i<pageFrameCount;i++){if(pageFrames[i]==pageNumber){pageFault = false;//upgrade pageTimestapstimestamps[i] = getPageFaultCount();break;}if(timestamps[i]<oldestTimestamp){oldestTimestamp = timestamps[i];oldestTimestampIndex = i;}}//if not in pagesFrame,happen faultsif(pageFault){pageFaultCount++;pageFrames[oldestTimestampIndex]=pageNumber;timestamps[oldestTimestampIndex]=getCurrentTimestamp();}}//acquire current timestampprivate  int getCurrentTimestamp(){return pageFaultCount+1;}
}
/*** Test harness for LRU and FIFO page replacement algorithms**/public class Test
{public static void main(String[] args) {if (args.length != 2) {System.err.println("Usage: java Test <reference string size> <number of page frames>");System.exit(-1);}PageGenerator ref = new PageGenerator(Integer.valueOf(args[0]).intValue());int[] referenceString = ref.getReferenceString();/** Use either the FIFO or LRU algorithms */ReplacementAlgorithm fifo = new FIFO(Integer.valueOf(args[1]).intValue());ReplacementAlgorithm lru = new LRU(Integer.valueOf(args[1]).intValue());// output a message when inserting a pagefor (int i = 0; i < referenceString.length; i++) {//System.out.println("inserting " + referenceString[i]);lru.insert(referenceString[i]);}// output a message when inserting a pagefor (int i = 0; i < referenceString.length; i++) {//System.out.println("inserting " + referenceString[i]);fifo.insert(referenceString[i]);}// report the total number of page faultsSystem.out.println("LRU faults = " + lru.getPageFaultCount());System.out.println("FIFO faults = " + fifo.getPageFaultCount());}
}

运行结果

参数设置 20-3

参数设置 20-4 

 思考

在实现了 FIFO 与 LRU 算法后,给定引用序列,试验不同页帧的数量所产
生的缺页次数。并分析:一个算法比另一好么?对给定引用序列,页帧的最佳数
量是多少?假设给定引用序列 1,2,3,4,1,2,5,1,2,3,4,5,当页帧
数分别为 3 和 4 时,用 FIFO 置换算法时缺页中断分别为多少?
根据代码,可以通过修改 Test 类的 main 方法中的 args 数组来改变页面帧的数量和引用序列的大小。以下是分别使用 FIFO 和 LRU 置换算法对给定引用序列进行测试的结果:
(1)当页帧数为 3 时:
使用 FIFO 置换算法,缺页次数为 9
使用 LRU 置换算法,缺页次数为 9

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81363.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发与AI融合的Windsurf编辑器

Windsurf编辑器是开发人员和人工智能真正融合在一起的地方&#xff0c;提供了一种感觉像文字魔术的编码体验。 手册&#xff1a;Windsurf - Getting Started 下载链接&#xff1a;Download Windsurf Editor for Windows | Windsurf (formerly Codeium) 下载安装 从上面的下载…

【Java】网络编程(Socket)

网络编程 Socket 我们开发的网络应用程序位于应用层&#xff0c;TCP和UDP属于传输层协议&#xff0c;在应用层如何使用传输层的服务呢&#xff1f;在应用层和传输层之间&#xff0c;则使用套接字Socket来进行分离 套接字就像是传输层为应用层开的一个小口&#xff0c;应用程…

【教程】Docker方式本地部署Overleaf

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 背景说明 下载仓库 初始化配置 修改监听IP和端口 自定义网站名称 修改数据存放位置 更换Docker源 更换Docker存储位置 启动Overleaf 创…

根据用户ID获取所有子节点数据或是上级直属节点数据

一、根据用户ID获取所有子节点&#xff0c;通过存储过程来实现 CREATE DEFINERcrmeb% PROCEDURE proc_get_user_all_children( IN rootUid INTEGER, -- 要查询的根用户ID IN includeSelf BOOLEAN -- 是否包含自身(1包含,0不包含) ) BEGIN -- 声明变…

计算机组成原理——数据的表示

2.1数据的表示 整理自Beokayy_ 1.进制转换 十六进制与二进制的转换 一位十六进制等于四位二进制 四位二进制等于一位十六进制 0x173A4C0001 0111 0011 1010 0100 1100 十六进制与十进制的转换 十六转十&#xff1a;每一位数字乘以相应的16的幂再相加 十转十六&#xff1a…

基于MATLAB-GUI图形界面的数字图像处理

基于MATLAB GUI的数字图像处理系统实现方案&#xff0c;包含常见图像处理功能。代码分为两部分&#xff1a;GUI界面设计和回调函数实现。 %% 第一部分&#xff1a;创建GUI界面 (使用GUIDE) % 1. 打开GUIDE: guide % 2. 创建新GUI&#xff0c;添加以下控件&#xff1a; % - …

从裸机开发到实时操作系统:FreeRTOS详解与实战指南

从裸机开发到实时操作系统&#xff1a;FreeRTOS详解与实战指南 本文将带你从零开始&#xff0c;深入理解嵌入式系统中的裸机开发与实时操作系统&#xff0c;以FreeRTOS为例&#xff0c;全面剖析其核心概念、工作原理及应用场景。无论你是嵌入式新手还是希望提升技能的开发者&am…

zabbix7.2最新版本 nginx自定义监控(三) 设置触发器

安装zabbix-get服务 在zabbix-server端口安装zabbix-get服务 [rootlocalhost ~]# dnf install -y zabbix-get Last metadata expiration check: 1:55:49 ago on Wed 14 May 2025 09:24:49 AM CST. Dependencies resolved. Package Architectur…

在 Kotlin 中,什么是解构,如何使用?

在 Kotlin 中&#xff0c;解构是一种语法糖&#xff0c;允许将一个对象分解为多个独立的变量。 这种特性可以让代码更简洁、易读&#xff0c;尤其适用于处理数据类、集合&#xff08;如 Pair、Map&#xff09;或其他结构化数据。 1 解构的核心概念 解构通过定义 componentN()…

html的鼠标点击事件有哪些写法

在HTML中&#xff0c;鼠标点击事件的实现方式多样&#xff0c;以下从基础语法到现代实践为您详细梳理&#xff1a; 一、基础写法&#xff1a;直接内联事件属性 在HTML标签内通过on前缀事件属性绑定处理函数&#xff0c;适合简单交互场景&#xff1a; <!-- 单击事件 -->…

基于EFISH-SCB-RK3576/SAIL-RK3576的智能垃圾分类站技术方案

&#xff08;国产化替代J1900的环保物联网解决方案&#xff09; 一、硬件架构设计‌ ‌多模态感知系统‌ ‌高精度识别模块‌&#xff1a; 双光谱成像&#xff08;RGB近红外&#xff09;融合NPU加速ResNet50模型&#xff0c;支持40垃圾品类识别&#xff08;准确率>99.5%&am…

PYTHON训练营DAY27

装饰器 编写一个装饰器 logger&#xff0c;在函数执行前后打印日志信息&#xff08;如函数名、参数、返回值&#xff09; logger def multiply(a, b):return a * bmultiply(2, 3) # 输出: # 开始执行函数 multiply&#xff0c;参数: (2, 3), {} # 函数 multiply 执行完毕&a…

Android Studio 中 build、assemble、assembleDebug 和 assembleRelease 构建 aar 的区别

上一篇&#xff1a;Tasks中没有build选项的解决办法 概述&#xff1a; 在构建 aar 包时通常会在下面的选项中进行构建&#xff0c;但是对于如何构建&#xff0c;选择哪种方式构建我还是处于懵逼状态&#xff0c;所以我整理了一下几种构建方式的区别以及如何选择。 1. build…

视频质量分析时,遇到不同分辨率的对照视频和源视频,分辨率对齐的正确顺序。

背景 我们平时在做视频转码后&#xff0c;会用VMAF/PSNR得评分工具进行视频对比的评分&#xff0c;但是这几种客观评分方式都有一个要求就是分辨率要一模一样&#xff0c;因为这样才对像素点做数学运算。 但是分辨率对齐其实有两种选择&#xff0c;例如源视频是1080P&#xf…

【技巧】离线安装docker镜像的方法

回到目录 【技巧】离线安装docker镜像的方法 0. 为什么需要离线安装&#xff1f; 第一、 由于docker hub被墙&#xff0c;所以 拉取镜像需要配置国内镜像源 第二、有一些特殊行业服务器无法接入互联网&#xff0c;需要手工安装镜像 1. 可以正常拉取镜像服务器操作 服务器…

计算机网络 : 网络基础

计算机网络 &#xff1a; 网络基础 目录 计算机网络 &#xff1a; 网络基础引言1. 网络发展背景2. 初始协议2.1 初始协议2.2 协议分层2.2.1 软件分层的好处2.2.2 OSI七层模型2.2.3 TCP/IP五层&#xff08;四层&#xff09;模型 2.3 TCP/IP协议2.3.1TCP/IP协议与操作系统的关系&…

【2025最新】Windows系统装VSCode搭建C/C++开发环境(附带所有安装包)

文章目录 为什么选择VSCode作为C/C开发工具&#xff1f;一、VSCode安装过程&#xff08;超简单&#xff01;&#xff09;二、VSCode中文界面设置&#xff08;再也不用对着英文发愁&#xff01;&#xff09;三、安装C/C插件&#xff08;编程必备神器&#xff01;&#xff09;四、…

Jmeter 安装包与界面汉化

Jmeter 安装包&#xff1a; 通过网盘分享的文件&#xff1a;CSDN-apache-jmeter-5.5 链接: https://pan.baidu.com/s/17gK98NxS19oKmkdRhGepBA?pwd1234 提取码: 1234 Jmeter界面汉化&#xff1a;

HandlerInterceptor介绍-笔记

1. HandlerInterceptor简介 org.springframework.web.servlet.HandlerInterceptor 是 Spring MVC 中用于拦截 HTTP 请求的核心接口。 public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object ha…

C++循环效率比较与优化建议

在 C++ 中,不同循环结构(如 for、while、do-while、基于范围的 for)在优化后的性能通常是等效的,因为现代编译器会对它们进行底层优化,生成相似的机器代码。循环的效率更多取决于循环体内的操作和数据访问模式,而非循环结构本身的选择。以下是关键点总结: 1. 传统循环的…