页面置换实验
16281259 鲁鑫
- 一、实验目的及基本要求
设计和实现最佳置换算法、先进先出置换算法、最近最久未使用置换算法、页面缓冲置换算法;通过页面访问序列随即发生器实现对上述算法的测试及性能比较。
- 二、页面置换算法知识背景说明
请求分页虚拟内存管理
- 三、工作集与缺页率
工作集:
多数程序都显示出高度的局部性,也就是说,在一段时间内,一组页面被反复引用。这组被反复引用的页面随着时间的推移,其成员也会发生变化。有时这种变化是剧烈的,有时这种变化则是渐进的。我们把这组页面的集合称为工作集。
缺页率:
缺页率=缺页中断次数/页面访问次数
- 四、实验内容
1.最佳置换算法(OPT)
基本思想:
选择永不使用或是在最长时间内不会再被访问(即距现在最长时间才会被访问)的页面淘汰出内存
评价:
理想化算法,具有最好性能(对于固定分配页面方式,本法可保证获得最低的缺页率),但实际上却难于实现,故主要用于算法评价参照。
2.先进先出置换算法(FIFO)
基本思想:
选择最先进入内存即在内存驻留时间最久的页面换出到外存;
进程已调入内存的页面按进入先后次序链接成一个队列,并设置替换指针以指向最老页面。
评价:
简单直观,但不符合进程实际运行规律,性能较差,故实际应用极少。
3.最近最久未使用置换算法(LRU)
基本思想:
以“最近的过去”作为“最近的将来”的近似,选择最近一段时间最长时间未被访问的页面淘汰出内存。
评价:
适用于各种类型的程序,性能较好,但需要较多的硬件支持。
上述三种算法在一个程序内实现,代码如下:
#include"iostream"
#include "stdio.h"
#include "stdlib.h"
using namespace std;
typedef struct item
{
int num; //页号
int time; //等待时间,LRU算法会用到这个属性
}Pro;
int pageNum; //系统分配给作业的主存中的页面数
int memoryNum; //可用内存页面数
void print(Pro* page1); //打印当前主存中的页面
int Search(int num1, Pro* memory1); //在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
int main(void)
{
int i;
int curmemory; //调入内存中的页面个数
int missNum; //缺页次数
float missRate; //缺页率
char c; //得到用户的输入字符,来选择相应的置换算法
Pro* page; //作业页面集
Pro* memory; //内存页面集
printf("输入系统分配给作业的主存中的页面数:");
scanf("%d", &pageNum);
printf("输入内存页面数:");
scanf("%d", &memoryNum);
page = (Pro*)malloc(sizeof(Pro) * pageNum);
memory = (Pro*)malloc(sizeof(Pro) * memoryNum);
for (i = 0; i < pageNum; i++)
{
printf("第 %d 个页面号为:", i);
scanf("%d", &page[i].num);
page[i].time = 0; //等待时间开始默认为0
}
do {
for (i = 0; i < memoryNum; i++) //初始化内存中页面
{
memory[i].num = -1; //页面为空用-1表示
memory[i].time = -1; //
}
printf("*****f:FIFO页面置换*****\n");
printf("*****o:OPT页面置换*****\n");
printf("*****l:LRU页面置换*****\n");
printf("*****请选择操作类型(f,o,l),按其它键结束******\n");
//fflush(stdin);
getchar();
scanf("%c", &c);
i = 0;
curmemory = 0;
if (c == 'f') //FIFO页面置换
{
missNum = 0;
printf("FIFO页面置换情况: \n");
for (i = 0; i < pageNum; i++)
{
if (Search(page[i].num, memory) < 0)//若在内存中没有找到该页面
{
missNum++;
memory[curmemory].num = page[i].num;
print(memory);
curmemory = (curmemory + 1) % memoryNum; //找出最先进入内存的页面
}
}//end for
missRate = (float)missNum / pageNum;
printf("缺页次数:%d 缺页率: %f\n", missNum, missRate);
}//end if
if (c == 'o') //OPT页面置换算法
{
missNum = 0;
curmemory = 0;
printf("Optimal页面置换情况: \n");
for (i = 0; i < pageNum; i++)
{
if (Search(page[i].num, memory) < 0)//若在内存中没有找到该页面
{
//找出未来最长时间内不再被访问的页面
int tem;
int opt = 0;
for (int k = 0; k < memoryNum; k++)
{
if (memory[k].num == -1)
{
curmemory = k;
break;
}
tem = 0; //页面k在未来tem时间内不会出现
int j;
for (j = i + 1; j < pageNum; j++)
{
if (page[j].num == memory[k].num)
{
if (tem > opt)
{
opt = tem;
curmemory = k;
}
break;
}
else tem++;
}
if (j == pageNum)
{
opt = tem;
curmemory = k;
}
}
missNum++;
memory[curmemory].num = page[i].num;
print(memory);
}
}//end for
missRate = (float)missNum / pageNum;
printf("缺页次数:%d 缺页率: %f\n", missNum, missRate);
}//end if
if (c == 'l') //LRU页面置换算法
{
missNum = 0;
curmemory = 0;
printf("LRU页面置换情况: \n");
for (i = 0; i < pageNum; i++)
{
int rec = Search(page[i].num, memory);
if (rec < 0) //若在内存中没有找到该页面
{
missNum++;
for (int j = 0; j < memoryNum; j++) //找出最近最久未使用的页面
if (memory[j].time == -1) {
curmemory = j; break;
}
else if (memory[j].time > memory[curmemory].time)
curmemory = j;
memory[curmemory].num = page[i].num;
memory[curmemory].time = 0;
print(memory);
}
else memory[rec].time = 0;
for (int j = 0; j < memoryNum; j++) //内存中的所有页面等待时间+1
if (memory[j].num != -1)
memory[j].time++;
}//end for
missRate = (float)missNum / pageNum;
printf("缺页次数:%d 缺页率: %f\n", missNum, missRate);
}//end if
} while (c == 'f' || c == 'l' || c == 'o');
return 0;
}
void print(Pro* memory1)//打印当前的页面
{
int j;
for (j = 0; j < memoryNum; j++)
printf("%d ", memory1[j].num);
printf("\n");
}
//在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
int Search(int num1, Pro* memory1)
{
int j;
for (j = 0; j < memoryNum; j++)
{
if (num1 == memory1[j].num)
return j;
}
return -1;
}
结果截图如下:
最佳置换算法:
先进先出置换算法:
最近最久未使用置换算法LRU结果截图:
4.改进型CLOCK置换算法
基本思想:
①从查寻指针当前位置起扫描内存分页循环队列,选择A=0且M=0的第一个页面淘汰;若未找到,转②
②开始第二轮扫描,选择A=0且M=1的第一个页面淘汰,同时将经过的所有页面访问位置0;若不能找到,转①
评价:
与简单CLOCK算法相比,可减少磁盘的I/O操作次数,但淘汰页的选择可能经历多次扫描,故实现算法自身的开销增大。
代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 20 //虚拟内存尺寸
using namespace std;
int P;
int const blockCount=3 ;//内存中的物理块数
int count = 0;
int block[blockCount];
int const PageCount=15;//总的页面数
int Page[PageCount];
int state[blockCount];//clock置换算法中,内存中的每个页面号对应的状态
int state2[blockCount][2];// 二维数组,第一行第一列为访问位,第一行的第二列为修改位
double lost= 0.0;
void generate_list(int *list,int e,int m,int t)
{
int i,j=0,q=P,r;
srand((unsigned)time(NULL));
while(j<e)
{
for(i=j;i<j+m;i++)
{
if(i==e)
break;
list[i]=(q+rand()%e)%N; //保证在虚拟内存的页号内
}
j=i;
r=rand()%100;
if(r<t)
q=rand()%N;
else
q=(q+1)%N;
}
}
//随机生产是否被修改的情况,prop(0……100),prop/100的概率为被修改
void generate_modify(int *mo,int e,int prop)
{
int i,t;
for(i=0;i<e;i++)
{
t=rand()%100;
if(t>prop)
mo[i]=0;
else
mo[i]=1;
}
}
//检测页号是否在内存中
bool inblock(int num)
{
for(int i=0; i<blockCount;i++)
{
if(block[i] == Page[num])
{
state[i] = 1;
return true;
}
}
return false;
}
//判断页面是否已经被修改
bool change()
{
if((rand()%2+1) == 1 )
{
printf("该页面被修改!\n");
return true;
}
else
return false;
}
//用于改进型clock置换算法,检测页号是否在内存中并把访问位和修改位置1
bool inblock2(int num)
{
for(int i=0;i<blockCount;i++){
if(block[i] == Page[num]){
if(change()){
state2[i][0] = 1;
state2[i][1] = 1;
}
else{
state2[i][0] = 1;
}
return true;
}
}
return false;
}
//用于改进型clock置换算法,判断内存中第几个需要被置换
int whichpage(){
int j;
for(j=0;j<blockCount;j++)
{
if(state2[j][0] == 0&&state2[j][1] == 0)
{
return j;
}
}
for(j=0;j<blockCount;j++ )
{
if(state2[j][0] == 0&&state2[j][1] == 1)
{
return j;
}
state2[j][0] = 0 ;
}
for(j=0;j<blockCount;j++ )
{
state2[j][0] =0 ;
}
return whichpage();
}
//简单Clock置换算法
void CLOCK(int num)
{
int j;
if(inblock(num))
{
printf("命中!\n");
lost++;
for(int i=0;i<blockCount;i++)
printf("物理块%d#中内容:%d\n",i,block [i]);
}
else
if(count == blockCount)
{
//lost++;
for(j=0;j<blockCount; )
{
if(state[j] == 0)
{
break;
}
else{
state[j] = 0;
}
j++;
j = j%3;
}
block[j] = Page[num];
state[j] = 1;
for(int i=0;i<blockCount;i++)
printf("物理块%d#中内容:%d\n",i,block[i]);
}
else{
block[count] = Page[num];
count++;
for(int i=0;i<blockCount;i++)
printf("物理块%d#中内容:%d\n",i,block[i]);
}
}
//改进型clock置换算法
void LCLOCK(int num)
{
int j;
if(inblock2(num))
{
printf("命中!\n");
lost++;
for(int i=0;i<blockCount;i++)
printf("物理块%d#中内容:%d\n",i,block[i]);
}
else
if(count == blockCount)
{
//lost++;
j = whichpage();
block[j] = Page[num];
state2[j][0] = 1;
for(int i=0;i<blockCount;i++)
printf("物理块%d#中内容:%d\n",i,block[i]);
}
else{
block[count] = Page[num];
count++;
for(int i=0;i<blockCount;i++)
printf("物理块%d#中内容:%d\n",i,block[i]);
}
}
int main()
{
int a[N];
int mo[N];
int A=10;
int e,m,prop,t,j;
printf("页面走向为:");
generate_list(a, e,m,t);
generate_modify(mo,e,prop);
for(int i = 0;i<PageCount;i++)
{
Page[i] =rand()%9 + 1;
printf("%d ",Page[i]);
}
char ch ;
printf("\n");
printf("\t\t1 Clock置换算法\n");
printf("\t\t2 改进型Clock置换算法\n");
printf("\t\t3 退出!\n\n");
printf("请输入算法序号:\t\n");
while(1){
scanf("%c",&ch);
switch(ch){
case '1':{
lost=0;
count=0;
for(int m=0;m<blockCount;m++)
{
state[m] = 0;
}
for(int j=0;j<blockCount;j++)
{
block[j]=0;
}
for(int i=0;i<PageCount;i++)
{
printf("读入Page[%d]\n",i);
CLOCK(i);
}
printf("页面访问次数: %d\n缺页次数: %0.lf\n",PageCount,PageCount-lost);
printf("缺页率为:%0.001f\n",(PageCount-lost)/PageCount);
printf("\n请输入算法序号:\t");
}break;
case '2':{
lost = 0;
count = 0;
for(int m = 0; m < blockCount; m++)
{
for(int n = 0; n < 2;n++)
state2[m][n] = 0;
}
for(int j = 0; j < blockCount; j++)
{
block[j] = 0;
}
for(int i = 0; i < PageCount; i++)
{
printf("读入Page[%d]\n",i);
LCLOCK(i);
}
printf("页面访问次数: %d\n缺页次数: %0.lf\n",PageCount,PageCount-lost);
printf("缺页率为:%0.001f\n",(PageCount-lost)/PageCount);
printf("\n请输入算法序号:\t");
}break;
case '3':{
exit(0);
}
}
}
return 0;
}
结果截图如下:
5.页面缓冲算法PBA
基本思想:
设立空闲页面链表和已修改页面链表;
采用可变分配和基于先进先出的局部置换策略,并规定被淘汰页先不做物理移动,而是依据是否修改分别挂到空闲页面链表或已修改页面链表的末尾;
空闲页面链表同时用于物理块分配;
当已修改页面链表达到一定长度如Z个页面时,一起将所有已修改页面写回磁盘,故可显著减少磁盘I/O操作次数。
- 五、课程假设前提说明
页表用整数数组或结构数组来表示;
页面访问序列串是一个整数序列,整数的取值范围为0到N-1。页面访问序列串中的每个元素p表示对页面p的一次访问。 - 六、页面访问序列随机生成说明
符合局部访问特性的随机生成算法。
1.确定虚拟内存的尺寸N,工作集的起始位置p,工作集中包含的页数e,工作集移动率m,以及一个范围在0和1之间的值t;
2.生成m个取值范围在p和p+e间的随机数,并记录到页面访问序列串中;
3.生成一个随机数r,0<=r<=1;
4.如果r<t,则为p生成一个新值,否则p=p+1modN;
5.如果想继续加大页面访问序列串的长度,请返回第二步,否则结束。 - 七、性能测评
测试不同的页面访问序列及不同的虚拟内存尺寸,并从缺页率、算法开销等方面对各个算法进行比较;
同时给出在给定页面访问序列的情况下,发生页面置换次数的平均值。
参考链接:https://wenku.baidu.com/view/4f6a8719312b3169a551a406.html
https://blog.csdn.net/AaricYang/article/details/72861566