目录
一、实验目的
1、理解页面调入策略中页面调入过程;
2、理解页面替换算法对缺页率的影响;
3、理解和掌握LRU算法和改进型CLOCK置换算法
二、实验内容
1、阐述页面调入过程中页面置换的基本过程;
2、阐述LRU算法和改进型CLOCK置换算法的思想;
3 、模拟实现,采用FIFO和LRU置换算法实现页面调入,计算缺页率和 替换次数。
三、实验原理
1.页面调入的基本过程
每当程序所要访问的页面为在内存时,便向CPU发起一缺页中断,中断处理程序首先保留CPU环境,分析中断原因后转入缺页中断处理程序。该程序通过查找页表得到该页的在外存的物理块后,若此时内存能容纳新页,则启动磁盘I/O,将所缺页调入内存,修改页表。如果内存已满,则须先按照某种置换算法,从内存中选出一页被换出。如果该页没有被修改过,可不必将其写回磁盘;但如果该页已经被修改过,则必须写回磁盘,然后将所缺的页调入内存,并修改页表中相应表项。
2.FIFO算法的基本原理
该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最长的页面予以淘汰。
3.LRU算法的基本原理
LRU置换算法选择最近最久没使用的页面予以淘汰。算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来经历的时间t。当需要淘汰一个页面时,选择现有页面中其t值最大的,即最近最久未使用的页面予以淘汰。
4.改进型CLOCK置换算法的基本原理
在将一个页面换出时,如果该页已被修改过,便须将该页重新写回到磁盘上;但如果该页未被修改过,则不必将它拷回磁盘。在改进型Clock算法中,除须考虑页面的使用情况外,还须在增加一个因素,即置换代价,这样页面换出时,既要是未使用过的页面,又要是未被修改过的页面。把同时满足这两个条件的页面作为首选淘汰的页面。由访问位A和修改位M可以组合成下面四种类型的页面:
1类(A=0,M=0):表示该页最近既未被访问,又未被修改,是最佳淘汰页。
2类(A=0,M=0):表示该页最近未被访问,但已被修改,并不是很好的淘汰页。
3类(A=1,M=0):表示该页最近已被访问,但未被修改,该页有可能在被访问。
4类(A=1,M=1):表示该页最近已被访问且被修改,该页可能再被访问。
四、实验思想
本次实验以模拟实现FIFO置换算法和LRU置换算法为例进行体会操作系统中页面置换的原理。算法原理如下图所示。
五、实验程序
实验数据:7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
import java.util.Scanner;
public class SubstituteTest {
void FIFO(PageFrame pageFrame,Frame[] frame){
System.out.println("******************** ********************");
System.out.println(" 页面置换之FIFO模拟开始 ");
System.out.println("******************** ********************");
int i = 0;
while(i < frame.length){
if(pageFrame.seek(frame[i])){//如果在内存中可以找到
System.out.println("页面:" + frame[i].value + ",命中");
}else{//找不到,缺页
if(pageFrame.total < pageFrame.pageFrame.length){
pageFrame.insert(frame[i]);
}else if(pageFrame.total == pageFrame.pageFrame.length){
pageFrame.replace(frame[i]);
}
//缺页的一些操作
frame[i].isMissPage = true;
System.out.print("页面:" + frame[i].value + ",未命中,替换后内存:");
pageFrame.showPage();
System.out.println();
}
i++;
}
}
void LRU(PageFrame pageFrame,Frame[] frame){
System.out.println("******************** ********************");
System.out.println(" 页面置换之LRU模拟开始 ");
System.out.println("******************** ********************");
int i = 0;
while(i < frame.length){
if(pageFrame.seek(frame[i])){//如果在内存中可以找到
System.out.println("页面:" + frame[i].value + ",命中");
}else {//找不到,缺页
if(pageFrame.total < pageFrame.pageFrame.length){
pageFrame.insertLRU(frame[i]);
}else if(pageFrame.total == pageFrame.pageFrame.length){
pageFrame.replaceLRU(frame[i]);
}
frame[i].isMissPage = true;
System.out.print("页面:" + frame[i].value + ",未命中,替换后内存:");
pageFrame.showPage();
System.out.println();
}
i++;
}
}
int sumMissPage(Frame[] frame){ //计算缺页的次数
int sum = 0;
for(int i = 0;i < frame.length;i++){
if(frame[i].isMissPage)sum++;
}
return sum;
}
void showResult(Frame[] frame,int n){ //展示结果
System.out.println("缺页个数:" + sumMissPage(frame) + ",置换次数:"
+ (sumMissPage(frame) - n) + ",缺页率: " + ((double)(sumMissPage(frame))/frame.length));
}
void selectWay(){
System.out.println("\n请选择您想要使用的调度算法:");
System.out.println("1.先进先出(FIFO)置换算法");
System.out.println("2.LRU置换算法");
System.out.print("请选择:");
}
int select(int se){//输入返回,方便以后功能的扩展
switch(se){
case 1:
return 1;
case 2:
return 2;
}
return 0;
}
void demo(){
Scanner scan = new Scanner(System.in);
System.out.print("输入页面个数:");
int n = scan.nextInt();
Frame[] pageFrame1 = new Frame[n];
PageFrame pageFrame = new PageFrame(pageFrame1);//创建内存的对象
System.out.print("输入页面个数:");
int m = scan.nextInt();
Frame[] frame = new Frame[m];//页面队列
System.out.println("输入页面访问队列:");
for(int i = 0;i < m;i++){
int num = scan.nextInt();
frame[i] = new Frame(num);//分别创建对象
}
selectWay();//选择哪种调度算法
int se = scan.nextInt();//输入选择
if(select(se) == 1){
FIFO(pageFrame,frame);
showResult(frame,n);
}else if(select(se) == 2){
LRU(pageFrame,frame);
showResult(frame,n);
}else{
System.out.println("选择错误");
}
}
public static void main(String[] args) {
SubstituteTest s = new SubstituteTest();
s.demo();
}
}
class Frame{
int value;//当前页面值
boolean isMissPage;//是否缺页,默认为false
public Frame(int value){
this.value = value;
}
}
class PageFrame{
Frame[] pageFrame;
int total;//记录内存有几个页面
int[] time;//记录页面调换次数(LRU)
public PageFrame(Frame[] pageFrame){
this.pageFrame = pageFrame;
time = new int[pageFrame.length];
}
public boolean seek(Frame frame){//在页表中寻找
for(int i = 0;i<total;i++){
if(pageFrame[i].value == frame.value){
time[i] = 0;//时间清为0,LRU算法
addOne(i);//分别加一
return true;
}
}
return false;
}
void showPage(){//显示当前内存页面情况
for (int i = 0; i < total; i++) {
System.out.print(pageFrame[i].value + " ");
}
}
public void insert(Frame frame){//如果找不到,且total<pageFrame.length,则插入
Frame[] f = new Frame[total];
for(int i = 0;i < total;i++){
f[i] = pageFrame[i];
}
pageFrame[0] = frame;//插入新的值
for (int i = 0; i < total; i++) {
pageFrame[i + 1] = f[i];//整体后移一位
}
total++;//增加记录的页面
}
public void replace(Frame frame){//如果找不到,且total==pageFrame.length,则替换
Frame[] f = new Frame[total - 1];
for(int i = 0;i < total - 1;i++){
f[i] = pageFrame[i];
}
pageFrame[0] = frame;//插入新的值
for(int i = 0; i < total - 1; i++) {
pageFrame[i + 1] = f[i];
}
}
public int maxTimeFrameId(){//返回最久未使用的页面号,一次只能调用一次,否则会改变结果
int max = 0,num = 0;
for (int i = 0; i < total; i++) {
if(time[i] > max){
max = time[i];
num = i;
}
}
return num;
}
public void addOne(int num){//除了所有为num的其它time[i]+1
for (int i = 0; i < total; i++) {
if(i != num){
time[i]++;
}
}
}
public void insertLRU(Frame frame){
pageFrame[total] = frame;//新加入的页面
time[total] = 0;//最新被调用,设置为0
addOne(total);//除了当前加入的页面,其余页面加1
total++;
}
public void replaceLRU(Frame frame){
int max = maxTimeFrameId();//必要的
pageFrame[max] = frame;
time[max] = 0;
addOne(max);
}
}
六、实验结果与截图
(1)FIFO
(2) LRU