一、实验目的
编程模拟实现存储器页面置换的常用算法,调试分析相关存储器管理程序,加深对存储器页面置换常用算法的理解和实现技巧
二、实验环境
VS2017+PC
三、实验内容
1.自定义存储器管理有关的数据结构;
2、依据最佳置换算法(Optimal)、先进先出置换算法(FIFO)、最近最久未使用算法(LRU)原理,编写对应函数,模拟系统的存储器页面置换功能;
3、为了更好地模拟和评价算法的性能,允许用户自行指定可用页块数并输入需访问的页面号序列;
4、统计以上算法实际需要的总页面数、缺页中断次数以及它们的缺页率;
5、比较/分析以上算法的置换性能,并作出自己的评价。
四、实验步骤
- 首先在主函数中,构造成一个界面,可以有选择界面以及物理块数的输入;
- 在上面写出函数,函数包括先进先出算法(FIFO),最佳算法(Optimal),最近最久算法(LRU);
- 设计每个算法的逻辑问题,例如:先进先出算法是在物理块中的页面号进行顺序的换进和换出;最佳算法是对后面的页面号不用的换出;最近最久算法是对前面的长时间不用的页面号进行换出。
- 对算法进行函数的编译,如物理块中的页面号没有满时,直接将页面放进去,直到满了之后,进行页面号的交换;
- 在进行代码的编译之后,开始进行对代码的测试;
- 输入测试数据,进行几次测试;
五、总结
通过此次实验,我对先进先出算法和最佳置换算法以及最近最久算法逻辑有了更深的理解,先前觉得先进先出算法和最近最久算法有点分不清楚,在做完这次实验之后,对这些基本概念有了彻底的理解。
六、代码
// Test1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include<map>
#include<set>
#include <algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 20
using namespace std;
int page[N];//页面引用号
int block[N];//物理块,内存
int dist[N][N];//表示第i次访问内存的时候,内存中的页面j 在以后被访问的最小时间
int n;//页面引用号个数
int m;//物理块数目
int page_max;//最大页面号
set<int>page_set;
//先进先出页面置换算法
int FIFO() {
int page_lack = 0;
memset(block, -1, sizeof(block));
int index = 1;
for (int i = 1; i <= n; ++i) {
if (index > m) index = 1;
set<int>::iterator it;
it = page_set.find(page[i]);
if (it == page_set.end()) {
if (block[index] != -1)
page_set.erase(block[index]);
page_set.insert(page[i]);
block[index++] = page[i];
++page_lack;
}
for (int k = 1; k <= m; ++k)
cout << block[k] << " ";
cout << endl;
}
cout << "FIFO进行了" << page_lack - m << "次页面置换" << endl;
return page_lack;
}
int pre[N];//page[i]在page中的索引
//最佳页面置换算法
int Optimal() {
int page_lack = 0;
memset(pre, 0, sizeof(pre));
memset(dist, 0x3f, sizeof(dist));
memset(block, -1, sizeof(block));
for (int i = n; i >= 1; --i) {
for (int j = 0; j <= page_max; ++j)
if (pre[j])
dist[i][j] = pre[j] - i;
pre[page[i]] = i;
}
for (int i = 1; i <= n; ++i) {//开始访问页面,初始是内存中没有分页
int j;
int max_dist = 0, p;
for (j = 1; j <= m; ++j) {
if (block[j] == -1) {//改块没有放入页面,则直接放入, 产生缺页
block[j] = page[i];
page_lack++;
break;
}
else if (block[j] == page[i])//页面存在内存中
break;
if (max_dist < dist[i][block[j]]) {
max_dist = dist[i][block[j]];//说明block[j] 对应的页面以后会长时间不会用到
p = j;//block[] 第j个页面会被替换掉
}
}
if (j > m) {//此时内存中不能在放入新的分页,而且没有找到page[i]对应的分页,接下来进行页面替换
block[p] = page[i];
page_lack++;
}
for (int k = 1; k <= m; ++k)//内存中页面加载情况
cout << block[k] << " ";
cout << endl;
}
cout << "Optimal进行了" << page_lack - m << "次页面置换" << endl;
return page_lack;//返回缺页次数
}
int LRU() {//最近最久未使用算法和opt算法差不多,只不过是lru是向前看, opt是向后看
int page_lack = 0;
memset(pre, 0, sizeof(pre));
memset(dist, 0x3f, sizeof(dist));
memset(block, -1, sizeof(block));
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= page_max; ++j)
if (pre[j])
dist[i][j] = i - pre[j];
pre[page[i]] = i;
}
for (int i = 1; i <= n; ++i) {//开始访问页面,初始是内存中没有分页
int j;
int max_dist = 0, p;
for (j = 1; j <= m; ++j) {
if (block[j] == -1) {//改块没有放入页面,则直接放入, 产生缺页
block[j] = page[i];
page_lack++;
break;
}
else if (block[j] == page[i])//页面存在内存中
break;
if (max_dist < dist[i][block[j]]) {
max_dist = dist[i][block[j]];//说明block[j] 对应的页面以后会长时间不会用到
p = j;//block[] 第j个页面会被替换掉
}
}
if (j > m) {//此时内存中不能在放入新的分页,而且没有找到page[i]对应的分页,接下来进行页面替换
block[p] = page[i];
page_lack++;
}
for (int k = 1; k <= m; ++k)//内存中页面加载情况
cout << block[k] << " ";
cout << endl;
}
cout << "LRU进行了" << page_lack - m << "次页面置换" << endl;
return page_lack;//返回缺页次数
}
int main() {
cout << "请输入页面个数:(形式为整数)";
cin >> n;
cout << "请输入物理块数目:(形式为整数)";
cin >> m;
cout << "请输入" << n << "个页面号:" << endl;
for (int i = 1; i <= n; ++i) {
cin >> page[i];
page_max = max(page_max, page[i]);
}
cout << "-----------------选择--------------------" << endl;
cout << "----------1.先进先出算法(FIFO)-----------" << endl;
cout << "----------2.最佳置换算法(Optimal)--------" << endl;
cout << "----------3.最近最久未使用算法(LRU)------" << endl;
cout << "请输入要进行的算法:(输入数字例如:1)" << endl;
while (1)
{
int choice;
cin >> choice;
switch (choice)
{
case 1:
FIFO();
break;
case 2:
Optimal();
break;
case 3:
LRU();
break;
default:
cout << "出错啦!" << endl;
}
}
return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件