三种页面置换算法
一、算法描述
1.先进先出(FIFO)置换算法
(1)描述:FIFO算法是最早出现的置换算法。该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。
(2)优点:该算法实现简单,只需要把一个进程已调入内存的页面按先后次序链接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的页面。
(3)缺点:该算法与进程实际运行的规律不相适应,因为在进程中,有些页面经常被访问,比如:含有全局变量、常用函数、例程等的页面,FIFO算法并不能保证这些页面不被淘汰。
2.最佳(Optimal)置换算法
(1)描述:最佳置换算法是由Belady于1966年提出的一种理论上的算法。其所选择的被淘汰的页面将是以后永不使用的,或许是在最长(未来)时间内不再被访问的页面。
(2)优点:采用最佳置换算法通常可以保证获得最低的缺页率。
(3)缺点:人们目前通常还无法预知,一个进程在内存的若干个页面中,哪一个页面是未来最长时间内不再被访问的,因此,该算法是无法实现的,但可以利用该算法去评价其他算法。
3.LRU(Least Recently Used)置换算法
(1)描述:最近最久未使用(LUR)的页面置换算法是根据页面调入内存后使用情况做出决策的。由于无法预测各页面将来的使用情况,只能利用“最近的过去”做“最近的将来”的近似,因此,LUR置换算法是选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间t。当需要淘汰一个页面时,选择现有页面中t值最大的,及最近最久未使用的页面予以淘汰。
(2)优点:考虑程序访问的时间局部性,一般能有较好的性能,实际应用多。
(3)缺点:实现会需要较多的硬件支持,会增加硬件成本。
4、CLCOK算法又称为最近未使用算法(NUR) 每页设置一个访问位,再将内存中的所有页面都通过链接指针链接成一个循环队列;当某个页面被访问时,其访问位置1。淘汰时,检查其访问位,如果是0,就换出;若为1,则重新将它置0;再按FIFO算法检查下一个页面,到队列中的最后一个页面时,若其访问位仍为1,则再返回到队首再去检查第一个页面。
二、代码实现
#include <stdio.h>
#include <stdlib.h>
typedef struct progress
{
int num; //页号
int time; //等待时间,LRU算法会用到这个属性
}Pro;//结构体定义,为变量提供一个新别名,方便变量的定义
int n; //页面个数
int m; //系统分配给进程的物理块数
void print(Pro *page1); //打印当前物理块中的页面
int Search(int num1, Pro *memory1); //在物理块memory1中查找页面号num1,如果找到,返回其在memory1中的下标,否则返回-1
int Max(Pro *memory1);
int optimal(int num,int tag,Pro *memory1,Pro *page1);
int main(void)
{
int i;
int curmemory; //调入物理块中的页面个数
int missNum; //缺页次数
float missRate; //缺页率
char c; //得到用户的输入字符,来选择相应的置换算法
Pro *page; //定义一个名为page的Pro类型的指针变量,页面集
Pro *memory; //定义一个名为memory的Pro类型的指针变量,物理块
printf("输入内存中的页面个数:");
scanf("%d", &n);
printf("输入系统为进程分配的最小物理块数:");
scanf("%d", &m);
page= (Pro*)malloc(sizeof(Pro)*n);//指针获取内存空间的大小
memory= (Pro*)malloc(sizeof(Pro)*m);
printf("输入页面个数为%d的页面序列:\n", n);
for(i=0;i<n;i++)
{
scanf("%d", &page[i].num);
page[i].time=0; //等待时间开始默认为0
}
do{
for(i=0;i<m;i++) //初始化物理块中页面
{
memory[i].num=-1; //页面为空用-1表示
memory[i].time=-1; //
}
printf("*****1-FIFO页面置换*****\n");
printf("*****2-OPT页面置换*****\n");
printf("*****3-LRU页面置换*****\n");
printf("*****请选择操作类型(1,2,3),按其它键结束*****\n");
fflush(stdin);//清空输入缓冲区
scanf("%c", &c);//得到用户的输入字符,选择相应的置换算法
i = 0;
curmemory = 0;
if(c=='1') //FIFO页面置换
{
missNum = 0;
printf("FIFO页面置换情况: \n");
for(i=0;i<n;i++)
{
if(Search(page[i].num,memory)<0)//若在物理块中没有找到该页面
{
missNum ++;
memory[curmemory].num=page[i].num;
print(memory);
curmemory = (curmemory+1)%m;
}
}//end for
missRate = (float)missNum/n;
printf("缺页次数:%d 缺页率: %f\n", missNum, missRate);
}//end if
if(c=='2') //OPT页面置换
{
missNum = 0;
printf("OPT页面置换情况: \n");
for(i=0;i<n;i++)
{
if(Search(page[i].num,memory)<0)//若在物理块中没有找到该页面
{
if(i<m)
curmemory = i;//调入物理块中的页面号为第i个页面的页面号
else
curmemory = optimal(page[i].num,i,memory,page);
missNum ++;
memory[curmemory].num=page[i].num;
print(memory);
curmemory = (curmemory+1)%m;
}
}//end for
missRate = (float)missNum/n;
printf("缺页次数:%d 缺页率: %.2f%%\n", missNum, missRate*100);
}//end if
if(c=='3') //LRU页面置换
{
missNum = 0;
printf("LRU页面置换情况: \n");
for(i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(memory[j].num>=0)
memory[j].time++;
}
if(Search(page[i].num,memory)<0)//若在物理块中没有找到该页面
{
missNum ++;
// printf("%d \n",curmemory);
if(i<m)
curmemory = i;//调入物理块中的页面号为第i个页面的页面号
else
curmemory = Max(memory);//调入物理块中的页面号为最先在物理块中出现的页面号
memory[curmemory].num=page[i].num;
memory[curmemory].time = 0;
print(memory);
curmemory = (curmemory+1)%m;
}
else
{
curmemory = Search(page[i].num,memory);
memory[curmemory].time=0;
curmemory = (curmemory+1)%m;
}
}//end for
missRate = (float)missNum/n;
printf("缺页次数:%d 缺页率: %.2f%%\n", missNum, missRate*100);
}//end if
}while(c=='1'||c=='2'||c=='3');
return 0;
}
void print(Pro *memory1)//打印当前的页面
{
int j;
for(j=0;j<m;j++)
printf("%d ", memory1[j].num);
printf("\n");
}
//在物理块memory1中查找页面号num1,如果找到,返回其在memory1中的下标,否则返回-1
int Search(int num1,Pro *memory1 )
{
int j;
for(j=0;j<m;j++)
{
if(num1==memory1[j].num)
return j;
}
return -1;
}
//替换掉物理块memory1中以后永不使用,或是未来在最长时间内不再被访问的页面号
int optimal(int num,int tag,Pro *memory1,Pro *page1)
{
int k,j,min[500],min_k;
for(k=0;k<m;k++)
min[k] = 500;
for(k=0;k<m;k++)
{
j = tag;//标记当前页号
do{
j++;
if(j>n)
break;
}while(page1[j].num!=memory1[k].num);//当前页面号未在物理块中出现,向后搜索
if(j<min[k])
{
min[k] = j;//找出以后永不使用,或是未来在最长时间内不再被访问的页面
}
}
int max = 0;
for(int t=1;t<m;t++)
{
if(min[t]>min[max])//物理块中出现的页面号和之后要用到的页面号的比较,找出最大下标
max = t;//把最大下标对应的页面号与物理块中出现的相同的页面号替换掉
}
return max;//返回以后永不使用,或是未来在最长时间内不再被访问的页面
}
//最早在物理块memory1中出现的页面号
int Max(Pro *memory1)
{
int max = 0;
for(int k=1;k<m;k++)
{
if(memory1[k].time > memory1[max].time)
max = k;
}
return max;//返回物理块等待时间最长的页面号
}
三、实验结果