操作系统实验四:页面置换实验

页面置换实验

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.如果想继续加大页面访问序列串的长度,请返回第二步,否则结束。
  • 七、性能测评
    测试不同的页面访问序列及不同的虚拟内存尺寸,并从缺页率、算法开销等方面对各个算法进行比较;
    同时给出在给定页面访问序列的情况下,发生页面置换次数的平均值。

GITHUB代码库

参考链接:https://wenku.baidu.com/view/4f6a8719312b3169a551a406.html
https://blog.csdn.net/AaricYang/article/details/72861566

  • 0
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值