页面置换算法实验(yss)
实验目的:
(1)设计和实现最佳(Optimal)置换算法、先进先出(FIFO)置换算法、最近最久未使用(Least Recently Used)置换算法、改进型Clock置换算法、页面缓冲算法(PBA);
(2)通过页面访问序列随机发生器实现对上述算法的测试及性能比较。
课题假设前提:
(1)模拟的虚拟内存的地址为16位,页面大小为1K,则最大虚拟物理块为64;
(2)模拟的物理内存有32K;
(3)页表用整数数组或结构数组来表示;
(4)页面访问序列串是一个整数序列,整数的取值范围为0到N - 1。页面访问序列串中的每个元素p表示对页面p的一次访问。
相关概念:
工作集:
多数程序都显示出高度的局部性,也就是说,在一个时间段内,一组页面被反复引用。这组被反复引用的页面随着时间的推移,其成员也会发生变化。有时这种变化是剧烈的,有时这种变化则是渐进的。我们把这组页面的集合称为工作集。
缺页率:
缺页率 = 缺页中断次数/页面访问次数
页面访问序列随机生成说明:(符合局部访问特性的随机生成算法)
(1)确定虚拟内存的尺寸N,工作集的起始位置p,工作集中包含的页数e,工作集移动率m(每处理m个页面访问则将起始位置p +1),以及一个范围在0和1之间的值t;
(2)生成m个取值范围在p和p + e间的随机数,并记录到页面访问序列串中;
(3)生成一个随机数r,0 ≤ r ≤ 1;
(4)如果r < t,则为p生成一个新值,否则p = (p + 1) mod N;
(5)如果想继续加大页面访问序列串的长度,请返回第2步,否则结束。
代码:
int SequenceCreation()//创建页面访问序列
{
int N,P,e,m,i=0,j=0,k=0,judge=0;
float t,r;
printf("请输入虚拟内存大小:\n");
scanf("%d",&N);
while(N>64)
{
printf("虚拟内存限制最大页数为64,请重新输入虚拟内存大小:\n");
scanf("%d",&N);
}
printf("请输入工作集的起始位置(P<N):\n");
scanf("%d",&P);
printf("请输入工作集包含的页数(e<N):\n");
scanf("%d",&e);
printf("请输入工作集移动率(m<N):\n");
scanf("%d",&m);
srand((unsigned)time(NULL));
t = 0.5;
do
{
for(j=0; j<m; j++)
{
record[j+k] = ((rand()%e)+P)%N;
}
k+=m;
r = rand()/32767.0;
if(r < t)
{
P = rand()%N;
}
else
{
P = (P+1)%N;
}
printf("如果想继续加大页面访问序列串的长度,请输入:1,否则输入0;\n");
printf("此时访问序列串的长度为:%d\n",k);
scanf("%d",&judge);
}
while(judge==1);
printf("页面访问序列串为:\n");
for(i = 0; i < k; i++)
{
printf("%d ",record[i]);
}
printf("\n");
return k;//返回页面访问序列串的长度
}
最佳置换算法
基本思想:
它是由Belady于1966年提出的一种理论上的算法。其所选择的被淘汰页面,将是以后永不使用的或许是在最长(未来)时间内不再被访问的页面。采用最佳置换算法,通常可保证获得最低的缺页率。但由于人目前还无法预知一个进程在内存的若干个页面中,哪一个页面是未来最长时间内不再被访问的,因而该算法是无法实现的,便可以利用此算法来评价其它算法。
评价:
理想化算法,具有最好性能(对于固定分配页面方式,本法可保证获得最低的缺页率),但实际上却难于实现,故主要用于算法评价参照。
代码:
int OPT()//最佳置换算法
{
int i;
missNum = 0;
curmemory = 0;
printf("最佳置换算法页面置换情况: \n");
for (i = 0; i<pageNum; i++)
{
if (Search(page[i].num, memory) < 0)//若在内存中没有找到该页面
{
//找出未来最长时间内不再被访问的页面
int tem;
int opt = 0;
int k;
for (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);
}
}
missRate = (float)missNum / pageNum;
printf("缺页次数:%d 缺页率: %f\n\n", missNum, missRate);
return 0;
}
先进先出置换算法
基本思想:
选择最先进入内存即在内存驻留时间最久的页面换出到外存。
进程已调入内存的页面按进入先后次序链接成一个队列,并设置替换指针以指向最老页面。
评价:
简单直观,但不符合进程实际运行规律,性能较差,故实际应用极少。
代码:
int FIFO()//先进先出页面置换算法
{
int i;
missNum = 0;
printf("先进先出页面置换算法页面置换情况: \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; //找出最先进入内存的页面
}
}
missRate = (float)missNum / pageNum;
printf("缺页次数:%d 缺页率: %f\n\n", missNum, missRate);
return 0;
}
最近最久未使用置换算法
基本思想:
以“最近的过去”作为“最近的将来”的近似。该算法赋予每一个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间t,当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面予以淘汰。
评价:
适用于各种类型的程序,性能较好,但需要较多的硬件支持。
代码:
int LRU()//最近最久未使用置换算法
{
int i;
missNum = 0;
curmemory = 0;
printf("最近最久未使用置换算法页面置换情况: \n");
for (i = 0; i<pageNum; i++)
{
int rec=Search(page[i].num, memory);
if (rec < 0) //若在内存中没有找到该页面
{
missNum++;
int j;
for (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;
int j;
for (j = 0; j<memoryNum; j++) //内存中的所有页面等待时间+1
if (memory[j].num != -1)
memory[j].time++;
}//end for
missRate = (float)missNum / pageNum;
printf("缺页次数:%d 缺页率: %f\n\n", missNum, missRate);
return 0;
}
改进型Clock置换算法
基本思想:
除考虑页面的使用情况外,还需再增加一个因素,即置换代价,选择页面换出时,既要是未使用过的页面,又要是未被修改过的页面。把同时满足这两个条件的页面最为首选淘汰的页面。由访问位A,修改位M可以组合成四种类型的页面
1类(A=0,M=0)该页面最近既未被访问,又未被修改,最佳淘汰页
2类(A=0,M=1)该页面最近未被访问,但已被修改,并不是最