页面置换算法
前言:
- 在地址映射过程中,若在页面中发现所要访问的页面不在内存中,则产生缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。
实验要求:
- 设计并实现最近最久未使用页面置换(LRU)算法;
- 实现最不常用页面置换算法(LFT),页面缓冲置换算法(PBA)和改进型CLOCK页面置
换算法(可选); - 编写测试程序,对不同页面置换算法的性能进行测试和比较。
本代码实现了最佳页面置换算法(OPT),先进先出置换算法(FIFO),最不常用置换算法(LFT),最近最久未使用置换算法(LRU)以及改进型CLOCK页面置换算法。
注: 改进型CLOCK页面置换算法仅仅实现算法思想。
算法思想
- 请到: 此处查看. 不要懒,百度百科你值得拥有。
- 如果代码需要在Linux内核中实现,请将页面下滑至最后,有你想要的。
C语言代码实现:
#include <stdio.h>
#include <stdlib.h>
int kh;
struct LNode
{
int data;
int flag;//访问位
int modify;//修改位
};//改进型Clock算法数据结构
//输出内存块页面序号
int OutputBlockofMemory(int *BlockofMemory, int BlockCount, int ReplacePage, int PageNum)
{
int i;
printf("访问页面 %d 后,", PageNum);
printf("内存中的页面号为:\t");
for(i = 0; i < BlockCount; i++)
{
if(BlockofMemory[i] < 0)
printf("# ");
else
printf("%d ", BlockofMemory[i]);
}
if(ReplacePage != -1)
printf("\t淘汰页面号为:%d", ReplacePage);
printf("\n");
return -1;
}
//输出页面引用串号
void OutputPageNumofRef(int* PageNumofRef, int PageNumRefCount)
{
int i = 0;
printf("页面引用串为:\t");
for(i = 0; i < PageNumRefCount; i++)
printf("%d ", PageNumofRef[i]);
printf("\n");
}
//内存块页面号清零
void ResetBlockofMemory(int *BlockofMemory, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
BlockofMemory[i] = -1;
}
//判断页是否在内存中,如果页在内存中,返回1,否则返回0;
int PageInBlockofMemory(int PageNum, int *BlockofMemory, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
if(PageNum == BlockofMemory[i])
return 1;
return 0;
}
//LFT算法判断页是否在内存中,如果页在内存中,返回1,相应计数器加1,否则返回0;
int PageInBlockofMemoryLFT(int PageNum, int *BlockofMemory, int BlockCount,int *sum)
{
int i;
for(i = 0; i < BlockCount; i++)
if(PageNum == BlockofMemory[i])
{sum[i]++;
return 1;}
return 0;
}
//下次访问次序
//参数j: 页面在内存块中的位置
//参数i: 页面号在页面号引用串中的位置
int DistanceOpt(int *BlockofMemory, int *PageNumofRef, int j, int i, int PageNumRefCount)
{
int k;
for(k = i + 1; k < PageNumRefCount; k++)
if(BlockofMemory[j] == PageNumofRef[k])
return k;
return PageNumRefCount;
}
//最佳页面置换算法
float Opt(int *BlockofMemory, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i, j, k;
int MaxIndex1, MaxIndex2;
int MissCount = 0;
int ReplacePage;
int EmptyBlockCount = BlockCount;
printf("**********最佳页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)
{
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
MaxIndex1 = MaxIndex2 = 0;
//求出未来最长时间不被访问的页
for(j = 0; j < BlockCount; j++)
{
MaxIndex2 = DistanceOpt(BlockofMemory, PageNumofRef, j, i, PageNumRefCount);
if(MaxIndex1 < MaxIndex2)
{
MaxIndex1 = MaxIndex2;
k = j;
}
}
ReplacePage = BlockofMemory[k];
BlockofMemory[k] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
{
OutputBlockofMemory(BlockofMemory,BlockCount, -1, PageNumofRef[i]);
}
}
printf("缺页次数为: %d\n", MissCount);
printf("OPT缺页率为: %.3f\n", (float)MissCount / PageNumRefCount);
return (float)MissCount / PageNumRefCount;
}
//最不常用页面置换算法
float LFT(int *BlockofMemory, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i, j, k=0,l;
int *sum;//为每个页面设置计数器
int MissCount = 0;
int ReplacePage;
int EmptyBlockCount = BlockCount;
sum = (int*)malloc(BlockCount * sizeof(int));//生成计数器
for(l=0;l<BlockCount;l++)
sum[l]=0;//初始化计数器
printf("**********最不常用页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemoryLFT(PageNumofRef[i], BlockofMemory, BlockCount,sum)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)//内存物理快有空间
{
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
sum[BlockCount - EmptyBlockCount]++;
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
for(j=0;j<BlockCount;j++)
if(sum[j]<sum[k])
k=j;
sum[k]=1;//被替换页面访问次数置1
ReplacePage = BlockofMemory[k];
BlockofMemory[k] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
{
OutputBlockofMemory(BlockofMemory,BlockCount, -1, PageNumofRef[i]);
}
}
printf("缺页次数为: %d\n", MissCount);
printf("LFU缺页率为: %.3f\n", (float)MissCount / PageNumRefCount);
return (float)MissCount / PageNumRefCount;
}
//先进先出页面置换算法
float Fifo(int *BlockofMemory,int *PageNumofRef,int BlockCount,int PageNumRefCount)
{
int i;
int ReplacePage;
int ReplaceIndex = 0;
int MissCount = 0;
int EmptyBlockCount = BlockCount;
printf("**********先进先出页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef,PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)
{
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
ReplacePage = BlockofMemory[ReplaceIndex];
BlockofMemory[ReplaceIndex] = PageNumofRef[i];
ReplaceIndex = (ReplaceIndex + 1) % BlockCount;
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
}
printf("缺页次数为:%d\n", MissCount);
printf("FIFO缺页率为:%.3f\n", (float)MissCount / PageNumRefCount);
return (float)MissCount / PageNumRefCount;
}
//内存块页面号清零
void ResetBlockofMemoryClock(struct LNode *nodes, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
{
nodes[i].data = -1;
nodes[i].data = -1;
nodes[i].data = -1;
}
}
int PageInBlockofMemoryclock(int PageNum, struct LNode *LNode, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
if(PageNum == LNode[i].data)
return 1;
return 0;
}
int OutputBlockofMemoryclock(struct LNode *LNode, int BlockCount, int ReplacePage, int PageNum)
{
int i;
printf("访问页面 %d 后,", PageNum);
printf("内存中的页面号为:\t");
for(i = 0; i < BlockCount; i++)
{
if(LNode[i].data < 0)
printf("# ");
else
printf("%d ", LNode[i].data);
}
if(ReplacePage != -1)
printf("\t淘汰页面号为:%d", ReplacePage);
printf("\n");
return -1;
}
float upclock(struct LNode *LNode, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i;
int *sum;//为每个页面设置计数器
int MissCount = 0;
int ReplacePage;
int EmptyBlockCount = BlockCount;
printf("**********改进Clock页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemoryclock(PageNumofRef[i], LNode, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)//内存物理快有空间
{
LNode[BlockCount - EmptyBlockCount].data = PageNumofRef[i];
LNode[BlockCount - EmptyBlockCount].flag = 1;
if( i % 2 == 0)
LNode[BlockCount - EmptyBlockCount].modify = 1;
else
LNode[BlockCount - EmptyBlockCount].modify = 0;
OutputBlockofMemoryclock(LNode, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
int j = 0, flag= -1;
while(1)
{
if((j / BlockCount) % 2 == 0)
{
if(LNode[j % BlockCount].flag == 0 && LNode[j % BlockCount].modify == 0)
{
flag = j % BlockCount;
break;
}//if
}//if
if((j / BlockCount) % 2 == 1)
{
if(LNode[j % BlockCount].flag == 0 && LNode[j % BlockCount].modify == 1)
{
flag = j % BlockCount;
break;
}//if
else
LNode[j % BlockCount].flag = 0;//访问位置0
}//if
j++;
}//close while
ReplacePage = LNode[flag].data;
LNode[flag].data = PageNumofRef[i];
LNode[flag].flag = 1;
if( i % 2 == 0)
LNode[flag].modify = 1;
else
LNode[flag].modify = 0;
OutputBlockofMemoryclock(LNode, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
{
OutputBlockofMemoryclock(LNode, BlockCount, -1, PageNumofRef[i]);
}
}
printf("缺页次数为: %d\n", MissCount);
printf("改进型clock算法缺页率为: %.3f\n", (float)MissCount / PageNumRefCount);
return (float)MissCount / PageNumRefCount;
}
//最近最久未使用页面置换算法
void count(int l,int *f) //数组未存满时,并且不在内存中 值最大要淘汰
{
int i;
if(l<5)
{
f[l]=1;
for(i=0;i<l;i++)
{
f[i]++;
}
}
l++;
}
int count1(int *f) //数组存满时,并且不在内存中 值最大要淘汰 b是指针
{
int a=0,b,i;
for(i=0;i<5;i++)
{
if(f[i]>a) {a=f[i];b=i;}
}
for(i=0;i<5;i++)
{
if(i==b) {}
else
{
if(f[i]<f[b]) f[i]++;
}
}
f[b]=1;
printf("%d",b);
return b;
}
void count2(int l,int *f) //在内存中
{
int i;
for(i=0;i<=l;i++)
{
if(i==kh) {}
else
{
if(f[i]<f[kh]) f[i]++;
}
}
f[kh]=1;
}
float Lru(int *BlockofMemory, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i,j=1;int l=0;int f[5];
int ReplacePage;
int ReplaceIndex = 0;
int MissCount = 0;
int EmptyBlockCount = BlockCount;
printf("************最近最久未使用页面置换算法:************\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)
{
count(l,f);
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
ReplacePage = BlockofMemory[count1(f)];
BlockofMemory[count1(f)] = PageNumofRef[i];
ReplaceIndex = (ReplaceIndex + 1) % BlockCount;
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
{
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
count2(l,f);
}
}
printf("缺页次数为:%d\n", MissCount);
printf("LRU缺页率为:%.3f\n", (float)MissCount / PageNumRefCount);
return (float)MissCount / PageNumRefCount;
}
int main()
{
int *BlockofMemory; //内存物理块
const int BlockCount = 3;
int i,j=0,k=0;
int PageNumofRef[] = {3,5,0,5,1,0,8,2,5,1,3}; //页面号引用串
int PageNumRefCount = sizeof(PageNumofRef) / sizeof(PageNumofRef[0]);
float t[5];
struct LNode *nodes = NULL;
nodes = (struct LNode*)malloc(BlockCount * sizeof(struct LNode));
BlockofMemory = (int*)malloc(BlockCount * sizeof(int));
if(BlockofMemory == (int*)NULL)
{
printf("内存分配出错\n");
exit(1);
}
ResetBlockofMemory(BlockofMemory, BlockCount);
t[0]=Opt(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
ResetBlockofMemory(BlockofMemory,BlockCount);
t[1] =Fifo(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
ResetBlockofMemory(BlockofMemory,BlockCount);
t[2] =LFT(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
ResetBlockofMemory(BlockofMemory,BlockCount);
t[3]=Lru(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
free(BlockofMemory);
ResetBlockofMemoryClock(nodes, BlockCount);
t[4] =upclock(nodes,PageNumofRef,BlockCount,PageNumRefCount);
free(nodes);
printf("\n");
printf("按缺页率从小到大排序结果如下:\n");
for(i=0;i<5;i++)
{
for(k=0;k<5;k++)
{
if(t[k]<t[j])
j=k;
}
switch(j)
{
case 0:printf("最佳置换算法的缺页率为:%.3f\n", t[0]);break;
case 1:printf("先进先出置换算法的缺页率为:%.3f\n", t[1]);break;
case 2:printf("最不常用置换算法的缺页率为:%.3f\n", t[2]);break;
case 3:printf("最近最久未使用置换算法的缺页率为:%.3f\n", t[3]);break;
case 4:printf("改进型clock置换算法的缺页率为:%.3f\n", t[4]);break;
}
t[j]=99;
}
return 0;
}
执行结果:
Linux实现步骤:
- 启动Engintime Linux Lab。
- 使用“Linux011应用程序”模板新建一个Linux011应用程序项目。项目名称可以
是“linuxapp”。 - 编辑LinuxApp.c文件,将main函数改为上面你复制的代码。【注】将注释全部删除,否则会报错。
- 按F7生成项目。
- 按F5启动调试
- 将生成的可执行文件从软盘B拷贝到硬盘,命令如下:
mcopy b:linuxapp.exe app
- 给app文件添加可执行权限,命令如下:
chmod +x app
- 执行“sync”命令,将对文件的更改保存到磁盘。
- 查看可执行文件app的信息,
ls –l app
- 运行可执行文件app,分析运行结果。
执行结果:
【注】由于不能滑动,只有这么大,不要见怪。