5种页面置换算法的简单实现
页面置换算法
OPT
最佳置换算法
- 缺点:最佳置换算法是一种理想化算法,具有较好的性能,但是实际上无法实现(无法预知一个进程中的若干页面哪一个最长时间不被访问);
- 优点:最佳置换算法可以保证获得最低的缺页率,性能最好
void opt() //最佳转换算法,往后查找
{
printf("--------------------------------\n");
printf("现在执行的是最佳置换算法opt:\n");
memset(arr, -1, sizeof(arr));
int no = 0, tot = 0, z = 0, three = 0;
int flag[8];
memset(flag, 0, sizeof(flag)); //初始化一个flag数组,来确定最晚出现需要替换的点
for (i = 0; i < M; i++)
{
if (no < N) //填充空数组
{
arr[no++] = pageNum[i];
tot++;
showdata();
}
else //当数组填充满后
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
}
if (z == 0)
{
for (int k = i + 1; k < M; k++) //从下一位向后查找
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[k] && three < (N-1)) //此位先出现则标记此位
{
if (flag[arr[j]] == 1)
continue;
flag[arr[j]] = 1;
three++;
}
}
}
for (int l = 0; l < N; l++) //遍历确定最长时间未被访问的页面
{
if (flag[arr[l]] == 1)
continue;
else
{
arr[l] = pageNum[i];
tot++;
showdata();
}
}
}
z = 0;
three = 0;
memset(flag, 0, sizeof(flag));
}
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("OPT缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
FIFO
先进先出算法
- 优点:先进先出算法实现简单,是最直观的一个算法
- 缺点:先进先出的性能最差,因为与通常页面的使用规则不符合,所以实际应用少
//FIFO先进先出算法
void fifo()
{
printf("--------------------------------\n");
printf("现在执行的是FIFO先进先出算法:\n");
memset(arr, -1, sizeof(arr));
int no = 0, z = 0, change = 0;
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
}
if (z == 0)
{
change++;
arr[no++] = pageNum[i];
showdata();
}
z = 0; //默认需要调度
if (no == N) //队列已满,则归0从头开始,等效于队头出队
no = 0;
}
printf("页面置换的次数为:%d\n", change);
double rate = (double)change / M * 100;
printf("FIFO缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
LFU
最少使用置换算法
- 缺点:并不能真正反映出页面的真实情况
- 优点:该算法既充分利用了主存中页面调度情况的历史信息,又正确反映了程序的局部性
void lfu() //最不经常使用算法,使用次数最少算法
{
printf("--------------------------------\n");
printf("现在执行的是最不经常使用算法lfu:\n");
int count[8], tot = 0, no = 0, z = 0, least = 100, mark = -1;
memset(arr, -1, sizeof(arr));
memset(count, 0, sizeof(count)); //用count数组记录访问次数,当访问次数相同时
for (i = 0; i < M; i++) //默认取索引较小的一位
{
if (no < N) //填充空数组
{
arr[no++] = pageNum[i];
tot++;
count[pageNum[i]]++;
showdata();
}
else
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
{
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
count[pageNum[i]]++;
}
}
if (z == 0)
{
for (int k = 0; k < N; k++) //通过循环比较出目前访问次数最小的页面进程
{
if (count[arr[k]] < least)
{
least = count[arr[k]];
mark = k;
}
}
arr[mark] = pageNum[i];
showdata();
tot++;
count[pageNum[i]]++;
}
z = 0;
least = 100;
mark = -1;
}
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("LFU缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
LRU
最近最久未使用置换算法
- 优点:由于考虑程序访问的时间局部性,一般能有较好的性能;实际应用多
- 缺点:实现需要较多的硬件支持,会增加硬件成本
void lru() //最近最久未访问算法,从当前位往前查找
{
printf("--------------------------------\n");
printf("现在执行的是最近最久未访问算法lru:\n");
memset(arr, -1, sizeof(arr));
int no = 0, tot = 0, z = 0, three = 0;
int flag[8];
memset(flag, 0, sizeof(flag)); //初始化一个flag数组,来确定最晚出现需要替换的点
for (i = 0; i < M; i++)
{
if (no < N) //填充空数组
{
arr[no++] = pageNum[i];
tot++;
showdata();
}
else //当数组填充满后
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
}
if (z == 0)
{
for (int k = i - 1; k >= 0; k--) //从上一位向前查找
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[k] && three < (N - 1)) //此位先出现则标记此位
{
if (flag[arr[j]] == 1)
continue;
flag[arr[j]] = 1;
three++;
}
}
}
for (int l = 0; l < N; l++) //遍历确定最长时间未被访问的页面
{
if (flag[arr[l]] == 1)
continue;
else
{
arr[l] = pageNum[i];
tot++;
showdata();
}
}
}
z = 0;
three = 0;
memset(flag, 0, sizeof(flag));
}
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("LRU缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
NRU
最近未用/时钟算法
- 优点:性能和开销比较均衡
- 缺点:未考虑页面是否被修改过
void nru() //clock置换算法/最近未用算法/NRU算法
{
printf("--------------------------------\n");
printf("现在执行的是clock置换算法nru:\n");
int ask[10], no = 0, tot = 0, z = 0, mark = 0;
memset(arr, -1, sizeof(arr));
memset(ask, 0, sizeof(ask)); //ask数组标记是否访问,1代表最近访问,0代表未访问
for (i = 0; i < M; i++)
{
if (no < N) //填充空数组
{
ask[no] = 1; //初始化为最近访问
arr[no++] = pageNum[i];
tot++;
showdata();
}
else
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
{
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
ask[j] = 1; //同时更新最近访问
}
}
if (z == 0)
{
int k = 0;
while (1) //通过循环找出访问位为0
{
for (k = 0; k < N; k++)
{
if (ask[k] == 0)
goto flag;
else if (ask[k] == 1)
ask[k] = 0;
}
}
flag:
arr[k] = pageNum[i];
ask[k] = 1;
showdata();
tot++;
}
}
z = 0;
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("NRU缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
代码实现(C语言)
#include <stdio.h>
#include <stdlib.h>
#define N 3
#define M 20
int i, j;
int arr[N];
int pageNum[M] = { 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1 };
void showdata()
{
for (int i = 0; i < N; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
//FIFO先进先出算法
void fifo()
{
printf("--------------------------------\n");
printf("现在执行的是FIFO先进先出算法:\n");
memset(arr, -1, sizeof(arr));
int no = 0, z = 0, change = 0;
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
}
if (z == 0)
{
change++;
arr[no++] = pageNum[i];
showdata();
}
z = 0; //默认需要调度
if (no == N) //队列已满,则归0从头开始,等效于队头出队
no = 0;
}
printf("页面置换的次数为:%d\n", change);
double rate = (double)change / M * 100;
printf("FIFO缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
void opt() //最佳转换算法,往后查找
{
printf("--------------------------------\n");
printf("现在执行的是最佳置换算法opt:\n");
memset(arr, -1, sizeof(arr));
int no = 0, tot = 0, z = 0, three = 0;
int flag[8];
memset(flag, 0, sizeof(flag)); //初始化一个flag数组,来确定最晚出现需要替换的点
for (i = 0; i < M; i++)
{
if (no < N) //填充空数组
{
arr[no++] = pageNum[i];
tot++;
showdata();
}
else //当数组填充满后
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
}
if (z == 0)
{
for (int k = i + 1; k < M; k++) //从下一位向后查找
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[k] && three < (N-1)) //此位先出现则标记此位
{
if (flag[arr[j]] == 1)
continue;
flag[arr[j]] = 1;
three++;
}
}
}
for (int l = 0; l < N; l++) //遍历确定最长时间未被访问的页面
{
if (flag[arr[l]] == 1)
continue;
else
{
arr[l] = pageNum[i];
tot++;
showdata();
}
}
}
z = 0;
three = 0;
memset(flag, 0, sizeof(flag));
}
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("OPT缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
void lru() //最近最久未访问算法,从当前位往前查找
{
printf("--------------------------------\n");
printf("现在执行的是最近最久未访问算法lru:\n");
memset(arr, -1, sizeof(arr));
int no = 0, tot = 0, z = 0, three = 0;
int flag[8];
memset(flag, 0, sizeof(flag)); //初始化一个flag数组,来确定最晚出现需要替换的点
for (i = 0; i < M; i++)
{
if (no < N) //填充空数组
{
arr[no++] = pageNum[i];
tot++;
showdata();
}
else //当数组填充满后
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
}
if (z == 0)
{
for (int k = i - 1; k >= 0; k--) //从上一位向前查找
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[k] && three < (N - 1)) //此位先出现则标记此位
{
if (flag[arr[j]] == 1)
continue;
flag[arr[j]] = 1;
three++;
}
}
}
for (int l = 0; l < N; l++) //遍历确定最长时间未被访问的页面
{
if (flag[arr[l]] == 1)
continue;
else
{
arr[l] = pageNum[i];
tot++;
showdata();
}
}
}
z = 0;
three = 0;
memset(flag, 0, sizeof(flag));
}
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("LRU缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
void lfu() //最不经常使用算法,使用次数最少算法
{
printf("--------------------------------\n");
printf("现在执行的是最不经常使用算法lfu:\n");
int count[8], tot = 0, no = 0, z = 0, least = 100, mark = -1;
memset(arr, -1, sizeof(arr));
memset(count, 0, sizeof(count)); //用count数组记录访问次数,当访问次数相同时
for (i = 0; i < M; i++) //默认取索引较小的一位
{
if (no < N) //填充空数组
{
arr[no++] = pageNum[i];
tot++;
count[pageNum[i]]++;
showdata();
}
else
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
{
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
count[pageNum[i]]++;
}
}
if (z == 0)
{
for (int k = 0; k < N; k++) //通过循环比较出目前访问次数最小的页面进程
{
if (count[arr[k]] < least)
{
least = count[arr[k]];
mark = k;
}
}
arr[mark] = pageNum[i];
showdata();
tot++;
count[pageNum[i]]++;
}
z = 0;
least = 100;
mark = -1;
}
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("LFU缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
void nru() //clock置换算法/最近未用算法/NRU算法
{
printf("--------------------------------\n");
printf("现在执行的是clock置换算法nru:\n");
int ask[10], no = 0, tot = 0, z = 0, mark = 0;
memset(arr, -1, sizeof(arr));
memset(ask, 0, sizeof(ask)); //ask数组标记是否访问,1代表最近访问,0代表未访问
for (i = 0; i < M; i++)
{
if (no < N) //填充空数组
{
ask[no] = 1; //初始化为最近访问
arr[no++] = pageNum[i];
tot++;
showdata();
}
else
{
for (j = 0; j < N; j++)
{
if (arr[j] == pageNum[i])
{
z = 1; //如果队列里已经存在此进程,则无需再进行页面调度
ask[j] = 1; //同时更新最近访问
}
}
if (z == 0)
{
int k = 0;
while (1) //通过循环找出访问位为0
{
for (k = 0; k < N; k++)
{
if (ask[k] == 0)
goto flag;
else if (ask[k] == 1)
ask[k] = 0;
}
}
flag:
arr[k] = pageNum[i];
ask[k] = 1;
showdata();
tot++;
}
}
z = 0;
}
printf("页面置换的次数为:%d\n", tot);
double rate = (double)tot / M * 100;
printf("NRU缺页率为:%.2lf%%\n", rate);
printf("--------------------------------\n");
}
int main()
{
fifo(); //先进先出算法
opt(); //最佳转换算法
lru(); //最近最久未使用
lfu(); //最不经常使用算法
nru(); //clock置换算法
return 0;
}