赞
踩
最近最久未使用(LRU)置换算法原理就是:当需要淘汰某页面时,选择当前一段时间内最久未使用过的页先淘汰,即淘汰距当前最远的上次使用的页。
例如: 分配给该进程的页块数为3,一个20位长的页面访问序列为:12560,36536,56042,70435,则缺页次数和缺页率按下图给出:
注:原实验指导书上图示有误,该图为笔者制作。
假定分配给该进程的页块数为3,页面访问序列长度为20。本实验可以采用数组结构实现,首先随机产生页面序列,当发生请求调页时,若内存已满,则需要利用LRU算法,将当前一段时间内最久未使用过的页替换出去。
模拟程序的算法如下图:
数组(数据结构)记录信息
int memory[1001]; //记录进程内存中的页
bool flag[1001]; //标记:访问的页面是否在内存中
int l_time[1001]; //记录页面的最近使用时间
int vis[1001]; //记录访问序列
bool miss[1001]; //记录每次访问的缺页状态
int state[1001][1001]; //记录每次访问后的进程的内存页面状态
整型变量
int n; //进程内存的页块数
int now_num = 0; //进程内存当前的页个数
int now_time = 0; //当前时间(访问次数)
int m; //页面访问序列的长度
int miss_num = 0; //缺页次数
缺页率
double miss_rate; //缺页率
自定义函数
void init()
:初始化void LRU(int a)
:LRU算法的实现void display()
:输出信息#include <iostream>
#include <queue>
#include <iomanip>
using namespace std;
int n; //进程内存的页块数
int now_num = 0; //进程内存当前的页个数
int now_time = 0; //当前时间(访问次数)
int m; //页面访问序列的长度
int miss_num = 0; //缺页次数
double miss_rate; //缺页率
int memory[1001]; //记录进程内存中的页
bool flag[1001]; //标记:访问的页面是否在内存中
int l_time[1001]; //记录页面的最近使用时间
int vis[1001]; //记录访问序列
bool miss[1001]; //记录每次访问的缺页状态
int state[1001][1001]; //记录每次访问后的进程的内存页面状态
//初始化
void init()
{
cout << "请输入分配给该进程的页块数:";
cin >> n;
cout << "请输入页面访问序列的长度:";
cin >> m;
cout << "请输入访问序列:";
for (int i = 0; i < m; i++)
{
cin >> vis[i];
}
//进程的内存中刚开始没有页,初始化为-1
for (int i = 0; i < n; i++)
{
memory[i] = -1;
}
//在内存中的标记初始化为false
for (int i = 0; i < 1000; i++)
{
flag[i] = false;
}
//页面的最近使用时间初始化为0
for (int i = 0; i < 1000; i++)
{
l_time[i] = 0;
}
return;
}
//LRU算法
void LRU(int a)
{
//检查请求访问的页是否在进程的内存中
if (flag[a] == false)
{
miss[now_time] = 1; //此次标记:缺页
miss_num++;
if (now_num == n) //内存已满
{
int min_time = 0x3f3f3f, min_num = -1;
//在内存中的页中,最早被访问时间和最久未使用过的页在内存中的编号
for (int i = 0; i < now_num; i++)
{
if (l_time[memory[i]] < min_time)
{
min_time = l_time[memory[i]];
min_num = i;
}
}
flag[a] = true; //将当前访问的页“是否在内存中”的标记设为1
flag[memory[min_num]] = 0; //将被替换的页“是否在内存中”的标记设为0
memory[min_num] = a; //当前页替换最久未使用过的页
}
else //内存未满
{
flag[a] = true;
memory[now_num] = a; //当前页进入内存的下一个位置
now_num++; //内存中页的个数加1
}
}
else
{
miss[now_time] = 0; //标记:未缺页
}
//保存内存中页面的序列
for (int i = 0; i < n; i++)
{
state[now_time][i] = memory[i];
}
l_time[a] = now_time; //更新当前页的被访问时间为当前时间
now_time++; //访问完一个页面,当前时间加1
return;
}
void display()
{
//输出表头
cout << "|访问|";
int left = n - n / 2 - 1;
int right = n / 2;
while (left--)
cout << " ";
cout << "序列";
while (right--)
cout << " ";
cout << "|是否缺页|" << endl;
for (int i = 0; i < m; i++)
{
cout << "|" << setw(4) << vis[i] << "|";
for (int j = 0; j < n; j++)
{
if (state[i][j] != -1)
cout << setw(4) << state[i][j];
else
cout << " ";
}
if (miss[i] == 1) //输出“是”和“否”比较丑
cout << "| 1 |" << endl;
else
cout << "| 0 |" << endl;
}
cout << "缺页次数:" << miss_num << endl;
miss_rate = (double)miss_num / m;
cout << "缺页率:" << miss_num << "/" << m << "=" << setprecision(2) << miss_rate << endl;
return;
}
int main()
{
init();
for (int i = 0; i < m; i++)
{
LRU(vis[i]);
}
display();
return 0;
}
分配给该进程的页块数:3
页面访问序列的长度:20
访问序列:1 2 5 6 0 3 6 5 3 6 5 6 0 4 2 7 0 4 3 5
与前文LRU算法的实现不同的是,在FIFO算法中,l_time[1001]
记录页面进入内存的时间。算法实现如下:
//FIFO算法
void FIFO(int a)
{
//检查请求访问的页是否在进程的内存中
if (flag[a] == false)
{
miss[now_time] = 1; //此次标记:缺页
miss_num++;
if (now_num == n) //内存已满
{
int min_time = 0x3f3f3f, min_num = -1; //被替换的页的入内存时间最早的页和位置
//在内存中的页中,先进先出(将入内存时间最早的页移出内存)
for (int i = 0; i < now_num; i++)
{
if (l_time[memory[i]] < min_time)
{
min_time = l_time[memory[i]];
min_num = i;
}
}
flag[a] = true; //将当前访问的页“是否在内存中”的标记设为1
flag[memory[min_num]] = 0; //将被替换的页“是否在内存中”的标记设为0
memory[min_num] = a; //当前页替换最早入内存的页
}
else //内存未满
{
flag[a] = true;
memory[now_num] = a; //当前页进入内存的下一个位置
now_num++; //内存中页的个数加1
}
l_time[a] = now_time; //更新当前页的入内存时间为当前时间
}
else
{
miss[now_time] = 0; //标记:未缺页
}
//保存内存中页面的序列
for (int i = 0; i < n; i++)
{
state[now_time][i] = memory[i];
}
now_time++; //访问完一个页面,当前时间加1
return;
}
简单的NRU算法是给每一帧关联一个附加位,称为使用位。当某一页首次装入主存时,该帧的使用位设置为1;当该页随后再被访问到时,它的使用位置为0。
对于页替换算法,用于替换的候选帧集合看做一个循环缓冲区,并且有一个指针与之相关联。当某一页被替换时,该指针被设置成指向缓冲区中的下一帧。当需要替换一页时,操作系统扫描缓冲区,以查找使用位被置为0的一帧。每当遇到一个使用位为1的帧时,操作系统就将该位重新置为0;如果在这个过程开始时,缓冲区中所有帧的使用位均为0,则选择遇到的第一个帧替换;如果所有帧的使用位均为1,则指针在缓冲区中完整地循环一周,把所有使用位都置为0,并且停留在最初的位置上,替换该帧中的页。
int u[1001]; //记录页面的使用位
int point; //指针
算法实现如下:
//NRU算法
void NRU(int a)
{
//检查请求访问的页是否在进程的内存中
if (flag[a] == false)
{
miss[now_time] = 1; //此次标记:缺页
miss_num++;
int num; //被替换的页的位置
if (now_num == n) //内存已满
{
//指针遍历内存
while (1)
{
if (u[memory[point]] == 1)
{
u[memory[point]] = 0; //将使用位为1的页面置为0
}
else //若使用位为0,被替换
{
num = point;
flag[a] = true; //将当前访问的页“是否在内存中”的标记设为1
flag[memory[num]] = 0; //将被替换的页“是否在内存中”的标记设为0
memory[num] = a; //当前页替换最久未使用过的页
break;
}
point++;
if (point >= n - 1)
{
point %= (n - 1);
}
}
}
else //内存未满
{
flag[a] = true;
memory[now_num] = a; //当前页进入内存的下一个位置
u[now_num] = 1; //使用位:置为1
now_num++; //内存中页的个数加1
point = now_num; //指针指向下一位置
}
}
else
{
miss[now_time] = 0; //标记:未缺页
u[now_num] = 0; //使用位:置为0
}
//保存内存中页面的序列
for (int i = 0; i < n; i++)
{
state[now_time][i] = memory[i];
}
now_time++; //访问完一个页面,当前时间加1
return;
}
无法预知一个进程中的若干页面哪一个最长时间不被访问,故无法实现。
优点:由于考虑程序访问的时间局部性,一般能有较好的性能;实际应用多。
缺点:实现需要较多的硬件支持,会增加硬件成本。
优点:先进先出算法实现简单,是最直观的一个算法。
缺点:先进先出的性能最差,因为与通常页面的使用规则不符合,所以实际应用少。
优点:近似于LRU算法,考虑了时间局部性,一般性能比LRU好。
缺点:同样需要较多的硬件支持,会增加硬件成本。
缺点:最佳置换算法是一种理想化算法,具有较好的性能,但是实际上无法实现(无法预知一个进程中的若干页面哪一个最长时间不被访问);
优点:最佳置换算法可以保证获得最低的缺页率
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。