实 验 报 告
学生姓名 | **,** | 学号 | ****** | 指导老师 | *** |
实验地点 | 实验时间 | 班级 | ***** |
- 实验室名称:
- 实验项目名称:
虚拟存储器管理
- 实验学时:
4学时
- 实验原理:
虚拟存储器作为现代操作系统中存储器管理的一项重要技术,实现了内存扩充功能。但该功能并非是从物理上实际地扩大内存的容量,而是从逻辑上实现对内存容量的扩充,让用户所感觉到的内存容量比实际内存容量大得多。于是便可以让比内存空间更大的程序运行,或者让更多的用户程序并发运行。这样既满足了用户的需要,又改善了系统的性能。
- 实验目的:
- 学习和编程实现最佳(OPT)页面置换算法
- 学习和编程实现先进先出(FIFO)页面置换算法。
- 学习和编程实现最近最久未使用(LRU)页面置换算法。
- 实验内容:
假定某进程共有8页,且系统为之分配了三个物理块,并有以下页面调度序列∶7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
使用以下置换算法:最佳置换算法(OPT)、先进先出置换算法(FIFO)、最近最少用置换算法(LRU)。
计算并输出:页面置换情况和缺页率。
最佳置换算法输出效果如下:
OPT:f=0.45 7x,0x,1x,2x,0,3x,0,4x,2,3 ,0x,3,2,1x,2,0,1,7x,0,1 |
- 最佳(OPT)页面置换算法:
- 流程图
- 算法分析和描述:
- 代码:
- 输出截图:
- 先进先出(FIFO)页面置换算法:
- 流程图
- 算法分析和描述:
- 代码:
- 输出截图:
- 最近最久未使用(LRU)页面置换算法:
- 流程图
- 算法分析和描述:
- 代码:
- 输出截图:
/**-------------------------------------------------实验开始--------------------------------------------------*/
1、最佳(OPT)页面置换算法:
(1)流程图:
- 算法分析和描述:
(3)代码:
#include <iostream>
int num[20] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
int A[3] = { -1, -1, -1 };
int physicalBlock[3] = { -1, -1, -1 }; // 3个物理块
bool OPT(int index) {
int i; //标识物理块号
for (i = 0; i < 3; i++) {
if (A[i] == -1) //判断该物理块是否为空物理块
break; //如果当前物理块为空物理块,则证明后面的物理块都为空物理块,需要装入页面。
if (physicalBlock[i] == num[index]) // 判断页面是否在内存中
return true;
}
if (i == 3) { //没有空物理块,需要替换页面
int flag = 0; // 标记有几个物理块的页面在随后的访问中被访问;
for (int m = index + 1; m < 20; m++) {
if (flag == 2) {
break;
}
for (int n = 0; n < 3; n++) { // 遍历物理块
if (num[m] == physicalBlock[n]) { // 该物理块的页面会在随后的访问中被访问
if (A[n] != 0) {
A[n] = 0;
flag++;
}
break;
}
}
}
for (int i = 0; i < 3; i++) {
if (A[i] != 0) {
physicalBlock[i] = num[index]; // 替换出该物理块中的页面
A[i] = 1; // 将标记改成有页面
}
A[i] = 1;
}
return false;
} else {
physicalBlock[i] = num[index]; //第i个物理块中放入页面
A[i] = 1;
return false;
}
}
void OPT1() {
int N = 0; //页面置换次数
for (int i = 0; i < 20; i++) {
bool b = OPT(i);
if (b == true) {
printf("%d ", num[i]);
}
if (b == false) { //页面发生了置换
printf("%dx ", num[i]);
N++;
}
}
double d = (double)N / 20 ;
printf("\nOPT:f=%.2f", d);
}
int main() {
OPT1();
}
(4)输出截图:
2.先进先出(FIFO)页面置换算法:
(1)流程图
(2)算法分析和描述:
(3)代码:
①主函数
#include<stdio.h>
#include<iostream>
#include "Queue.h"
using namespace std;
void FIFO(int order[20],int visitied[20])
{
cout<<"先进先出置换算法输出效果如下:"<<endl;
SqQueue Q;InitQueue(Q); //创建并初始化队列
int i,j;
float flag=0,per; //缺页次数与缺页率
for(i=0;i<20;i++) //所要调度序列长度
{
if(Queue_FInd(Q,order[i])) //判断是否缺页
{//不缺
visitied[i]=1;
continue;
}
else
{//缺页
flag+=1;//缺页次数+1
if(QueueFull(Q)) //判断物理块是否有剩余
{//物理块用光了
DeQueue(Q,j); //FIFO //队头出队
EnQueue(Q,order[i]); //队尾进队
}
else //使用剩余物理块
{//物理块还有剩的
EnQueue(Q,order[i]); //入队
}
visitied[i]=0;
}
}
per=flag/20;
printf("FIFO:f=%.2f\n",per);
}
int main()
{
int Order[20]={7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1};
int visitied[20]; //为保持输出与规定的一样,现创建一个数组;缺页置0,不缺置1;
FIFO(Order,visitied);
for(int i=0;i<20;i++)
{
if(visitied[i]==0)
{
cout<<Order[i]<<'x'<<'\t';
}
else
{
cout<<Order[i]<<'\t';
}
}
return 0;
}
②头文件——Queue.h
#include<stdio.h>
#include<iostream>
using namespace std;
#define MAXSIZE 4 //定义物理块数。实际使用中会少用一个空间来实现循环 队列
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
typedef struct
{
int *base; ///顺序表要加*号,要给空间,存基地址
//or int data[MAXSIZE];
int Front;
int Rear;
}SqQueue;
///初始化
Status InitQueue(SqQueue &Q)
{
Q.base=new int[MAXSIZE];
if(!Q.base) exit(OVERFLOW);
Q.Front=Q.Rear=0;
return OK;
}
///入队
Status EnQueue(SqQueue &Q,int e)
{
if((Q.Rear+1)%MAXSIZE==Q.Front) return OVERFLOW;
Q.base[Q.Rear]=e;
Q.Rear=(Q.Rear+1)%MAXSIZE; ///防溢出
return OK;
}
///出队
Status DeQueue(SqQueue &Q,int &E)
{
if(Q.Front==Q.Rear) return ERROR;
E=Q.base[Q.Front];
Q.Front=(Q.Front+1)%MAXSIZE;
return OK;
}
///求队列长度
Status QueueLength(SqQueue Q)
{
return (Q.Rear-Q.Front+MAXSIZE)%MAXSIZE;
}
///get head Elem
Status GetHead(SqQueue Q)
{
if(Q.Front!=Q.Rear)
{
return Q.base[Q.Front]; //队头指针不变
}
}
///判空
Status QueueEmpty(SqQueue Q)
{
if(Q.Front==Q.Rear) return OK;
else return ERROR;
}
///判满
bool QueueFull(SqQueue Q)
{
if((Q.Rear+1)%MAXSIZE==Q.Front) return true;
else return false;
}
///遍历队列查找
bool Queue_FInd(SqQueue Q,int E)
{
int i,head,rear;
head=Q.Front;rear=Q.Rear;
/*if(QueueEmpty(Q))
{
cout<<"队列为空";
return false;
}*/
for(i=0;i<QueueLength(Q);i++)
{
if(Q.base[head]==E)
{
return true;
}
head=(head+1)%MAXSIZE;
}
if(i==QueueLength(Q))
{
return false;
}
}
///打印队列
int Queue_Printf(SqQueue Q)
{
int i,head;
head=Q.Front;
if(QueueEmpty(Q))
{
cout<<"队列为空";
return ERROR;
}
for(i=0;i<QueueLength(Q);i++)
{
cout<<Q.base[head]<<endl;
head=(head+1)%MAXSIZE;
}
}
(4)输出截图:
3.最近最久未使用(LRU)页面置换算法:
(1)流程图
(2)算法分析和描述:
(3)代码:(头文件——Queue.h 同上 此处略)
#include<stdio.h>
#include<iostream>
#include "Queue.h"
using namespace std;
///交换数值
void Swap(int &a,int &b)
{
int t;
t=a;
a=b;
b=t;
}
/**-----改变队列内元素顺序----*/
void Change_QElem(SqQueue &Q,int E)
{
int L,Locate2;
L=(Q.Front+QueueLength(Q)-1)%MAXSIZE; //确定队尾元素的位置
Locate2=(Q.Front+1)%MAXSIZE; //确定队头后一个元素的位置
if(Q.base[L]==E);//队尾元素是最新页,无需变换队列元素顺序
else
{//队尾元素不是最新页
if(L==Locate2) //队列只有两个元素时
{
Swap(Q.base[L],Q.base[Q.Front]); //两个元素进行交换
}
else //队列有三个元素时即队满,有两种情况:①队头是最新页②队头后一个元素是最新页
{
if(Q.base[Q.Front]==E) //①
{
//方法一:利用第四个空间
Q.base[Q.Rear]=Q.base[Q.Front];
Q.base[Q.Front]=NULL;
Q.Front=(Q.Front+1)%MAXSIZE;
Q.Rear=(Q.Rear+1)%MAXSIZE;
//方法二:两次交换
/*Swap(Q.base[Q.Front],Q.base[Locate2]);
Swap(Q.base[Locate2],Q.base[L]);*/
}
else //②
{
Swap(Q.base[L],Q.base[Locate2]); //两个元素进行交换
}
}
}
}
/**-------LRU--------*/
void LRU(int Order[20],int visited[20])
{
int i=0,E;
float flag=0,per; //定义缺页次数与缺页率
SqQueue Q;InitQueue(Q);
for(i=0;i<20;i++)
{
if(Queue_FInd(Q,Order[i])) //判断是否缺页
{//不缺页
visited[i]=1;
Change_QElem(Q,Order[i]); ///按最近最久来重新排序队列内元素
}
else
{//缺页
flag+=1; //缺页次数+1
if(QueueFull(Q)) //判断物理块是否有剩余
{//无剩余
DeQueue(Q,E); //队头(最近最久未使用的页)出队
EnQueue(Q,Order[i]);
}
else
{//有剩余
EnQueue(Q,Order[i]);
}
visited[i]=0;
}
}
per=flag/20;
cout<<"最佳置换算法输出效果如下"<<endl;
printf("LRU:f=%.2f\n",per);
}
int main()
{
int Order[20]={7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1};
int visitied[20]; //为保持输出与规定的一样,现创建一个数组;缺页置0,不缺置1;
LRU(Order,visitied);
for(int i=0;i<20;i++)
{
if(visitied[i]==0)
{
cout<<Order[i]<<'x'<<'\t';
}
else
{
cout<<Order[i]<<'\t';
}
}
return 0;
}
(4)输出截图: