在进程运行过程中,若所要访问的页面不在内存,而需把它调入内存,但内存已无空闲区间时,为了保证该进程能正常运行,系统必须从内存中调出一页程序或数据送到磁盘空间的对换区中。将那个页面换出,需要根据一定的算法来确定。这就是页面置换算法。
最佳(Optimal)置换算法,选择的淘汰页将是以后永久不使用的,或许是在最长时间内不再访问的页面。这种算法可以保证最低的缺页率,但该算法真实情况下无法实现,可以作为评价其他算法的标准。
先进先出(FIFO)页面置换算法,总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以换出。只需把一个进程已调入的页面连成一个队列,每次换出队首进程。这种算法与实际进程运行规律不适应。
LRU(Least Recently Used)置换算法,选择最近最久未使用的页面予以换出。该算法赋予每个页面访问字段,用来记录一个页面上一次被访问以来的时间t。淘汰时选择t最大的页面换出。
具体代码如下:
#include <iostream>
#include <stdio.h>
#include <queue>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define MaxNumber 100
int MinBlockNum, PageNum, LackPageNum; //物理块数,页面个数,缺页数
int *MinBlock;//物理块数组
double LackPageRate; //缺页率
int PageOrder[MaxNumber]; //页面序列
int *PageDisCount; //当前内存距离下一次出现的距离
int *LRUtime; //存储各个页面最近使用情况
void Enter(); //输入物理块数、页面号顺序
void FIFO(); //先进先出FIFO
void OPT(); //最佳置换OPT
void LRU(); //最近最久未使用LRU
void display(); //显示执行结果
int find(int* a, int x); //查看页面在物理块中是否存在
int OPTCalculateInstance(int i, int j, int* a); //OPT向后计算距离
int LRUCalculateInstance(int i, int j, int* a); //LRU向前计算距离
int max_index(int* a); //找最大值下标
int main()
{
Enter();
//动态为数组分配空间
MinBlock = (int*)malloc(sizeof(int) * MinBlockNum);
PageDisCount = (int*)malloc(sizeof(int) * MinBlockNum);
LRUtime= (int*)malloc(sizeof(int) * MinBlockNum);
printf("\nOPI:\n");
OPT();
memset(MinBlock, -100, sizeof(int)* MinBlockNum); //重新初始化,以免影响后面程序执行
printf("\nFIFO:\n");
FIFO();
memset(MinBlock, -100, sizeof(int) * MinBlockNum);
printf("\nLRU:\n");
LRU();
//释放内存
free(MinBlock);
free(PageDisCount);
free(LRUtime);
return 0;
}
void Enter() //初始化物理块数、页面号顺序
{
printf("Enter MinBlockNum:");//输入物理块数
scanf("%d", &MinBlockNum);
printf("Enter PageNum:"); //页面数
scanf("%d", &PageNum);
printf("Enter PageOrder:"); //页面序列
for (int i = 0;i < PageNum;i++) {
scanf("%d", &PageOrder[i]);
}
}
int find(int *a,int x) //查看页面在物理块中是否存在
{//把传入的页面x与物理块a中页面进行比对
for (int i = 0;i<MinBlockNum;i++) {
if (x == a[i]) { //找到返回
return i;
}
}
return -1; //遍历结束表示传入的页面不在物理块中,返回-1
}
//物理块中的几个页面需要循环调用此函数,计算下一次出现的距离
int OPTCalculateInstance(int i, int j, int* a) //OPT向后计算距离
{//i表示页面序列里的下标,j表示目前物理块中的某个页面,a是页面序列
int k = i;
int count = 0;
while (k < PageNum && j != a[k]) { //当页面序列的页面与物理块页面j不匹配时向后遍历
count++; //距离++
k++; //下标
}
if (k >= PageNum) //找到最后都没找到与j对应的页面,返回距离+1
return count + 1;
else
return count; //这步说明找到了相同的页面
}
//物理块中的几个页面需要循环调用此函数,计算前一次出现的距离
int LRUCalculateInstance(int i, int j, int* a)
{//这个向前计算距离,反向遍历页面序列
int k = i;
int count = 0;
while (k>=0 && j != a[k]) {
count++;
k--;
}
if (k < 0)
return count + 1;
else
return count;
}
int max_index(int *a) //找到最大值,返回数组下标
{
int k=0;
int max = a[0];
for (int i = 1;i<MinBlockNum;i++) {
if (a[i] > max) {
max = a[i];
k = i;
}
}
return k;
}
void FIFO() //先进先出FIFO //10
{
int i = 0, j = 0;
LackPageNum = 0;
queue<int>QBlock; //初始化队列
while (i< PageNum)
{
if (-1 == find(MinBlock, PageOrder[i])) //如果要进入的页面不在物理块中
{
if (j < MinBlockNum) //物理块没满时
{//页面进入物理块
MinBlock[j++] = PageOrder[i];
QBlock.push(PageOrder[i]); //页面入队
}
else //物理块满了,需要考虑换出的页面是哪一个
{
for (int k = 0;k < MinBlockNum;k++)
{
if (MinBlock[k] == QBlock.front()) //队首页面永远是最早进来的,替换物理块中对应的页面
{
MinBlock[k] = PageOrder[i]; //新页面覆盖那个进入物理块最久的页面
QBlock.pop();
QBlock.push(PageOrder[i]); //刚进来的页面入队
break;
}
}
}
display();
LackPageNum++; //缺页数++
}
else //如果要进入的页面在物理块中,表示不缺页
printf("****************\n");
i++;
}
printf("LackPageNum:%d\n", LackPageNum);
printf("LackPageRate:%.2f\n", 1.0 * LackPageNum / PageNum);
}
void OPT() //最佳置换OPI //8
{
int i = 0, j = 0;
LackPageNum = 0;
while (i < PageNum) {
if (-1 == find(MinBlock, PageOrder[i])) { //如果要进入的页面不在物理块中
if (j < MinBlockNum) //物理块没满时
{//页面直接进入物理块
MinBlock[j++] = PageOrder[i];
}
else //物理块满了,需要考虑换出的页面是哪一个
{
for (int k = 0;k < MinBlockNum;k++)
{//遍历物理块的页面
PageDisCount[k] = OPTCalculateInstance(i+1, MinBlock[k], PageOrder); //计算物理块中页面与下一次的相同页面的距离
}
int max_i = max_index(PageDisCount); //比较物理块中页面哪个最远
MinBlock[max_i] = PageOrder[i]; //把距离最远的页面换出去,使其被覆盖;
}
display();
LackPageNum++; //缺页数++
}
else //如果要进入的页面在物理块中,表示不缺页
printf("****************\n");
i++;
}
printf("LackPageNum:%d\n", LackPageNum);
printf("LackPageRate:%.2f\n", 1.0*LackPageNum / PageNum);
}
void LRU() //最近最久未使用LRU //11
{
int i = 0, j = 0;
LackPageNum = 0;
while (i < PageNum) {
if (-1 == find(MinBlock, PageOrder[i])) { //如果要进入的页面不在物理块中
if (j < MinBlockNum) //物理块没满时
{//页面直接进入
MinBlock[j++] = PageOrder[i];
}
else //物理块满了,需要考虑换出的页面是哪一个
{
for (int k = 0;k < MinBlockNum;k++)
{//遍历物理块的页面
LRUtime[k] = LRUCalculateInstance(i-1,MinBlock[k],PageOrder); //计算物理块中页面与前一次被访问过的相同页面的距离
}
int max_i = max_index(LRUtime); //距离最大表示最久没有被访问
MinBlock[max_i] = PageOrder[i]; //新页面覆盖对应页面
}
display();
LackPageNum++; //缺页数++
}
else //如果要进入的页面在物理块中,表示不缺页
printf("****************\n");
i++;
}
printf("LackPageNum:%d\n", LackPageNum);
printf("LackPageRate:%.2f\n", 1.0 * LackPageNum / PageNum);
}
void display() //显示物理块页面
{
for (int i = 0;i < MinBlockNum;i++) {
if (MinBlock[i] >= 0)
printf("%d ", MinBlock[i]);
}
printf("\n");
}
物理块数3,页面数20。
页面序列7 0 7 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
运行结果如下:
最佳算法:
先进先出算法:
最近最久未使用算法: