课程设计开始了,实验很有意思,写博客总结学到的知识
白嫖容易,创作不易,学到东西才是真
本文原创,创作不易,转载请注明!!!
本文链接
个人博客:https://ronglin.fun/archives/181
PDF链接:见博客网站
CSDN: https://blog.csdn.net/RongLin02/article/details/118309055
为了美观,实验源代码在结尾处,整合版见下
链接:https://pan.baidu.com/s/1rXj1QJGuw-BVc5sQWret9w
提取码:Lin2
操作系统课程设计源代码
本次操作系统课程设计合集
操作系统课设之Windows 进程管理
操作系统课设之Linux 进程管理
操作系统课设之Linux 进程间通信
操作系统课设之Windows 的互斥与同步
操作系统课设之内存管理
操作系统课设之虚拟内存页面置换算法的模拟与实现
操作系统课设之基于信号量机制的并发程序设计
操作系统课设之简单 shell 命令行解释器的设计与实现
仅用于学习,如有侵权,请联系我删除
虚拟内存页面置换算法的模拟与实现
通过对页面、页表、地址转换和页面置换过程的模拟,加深对虚拟页式内存管理系统的页面置换原理和实现过程的理解。
需要调入新页面时,选择内存中哪个物理页面被置换,称为置换策略。页面置换算法的目标:
把未来不再使用的或短期内较少使用的页面调出,通常应在局部性原理指导下依据过去的统计数据进行预测,减少缺页次数。
本次模拟的页面置换算法有:
1)最佳置换算法(OPT):置换时淘汰“未来不再使用的”或“在离当前最远位置上出现的”页面。
2)先进先出置换算法(FIFO):置换时淘汰最先进入内存的页面,即选择驻留在内存时间最长的页面被置换。
3)最近最久未用置换算法(LRU):置换时淘汰最近一段时间最久没有使用的页面,即选择上次
同时为了兼顾程序的局部性原理,要通过随机数产生一个指令序列
① 50%的指令是顺序执行的;
② 25%的指令是均匀分布在前地址部分;
③ 25%的指令是均匀分布在后地址部分; 这样生成的指令序列是随机且有局部性
本次代码设计一共包括三大部分,第一大部分就是数据结构的设计,页框、指令的数据类型等;第二大部分是指令序列的生成,要根据题目要求生成一个体现局部性原理的随机数列;第三大部分就是要模拟实现OPT,FIFO,LRU算法。
页框的数据结构
struct MemoryCell
{
int index;//页号
int time;//时间戳
};
因为要兼顾3种算法,尤其是LRU,增加了一个时间戳,所以页框数据类型最后确定如上
int commds[COMMD_NUM]; //存放的是每一条指令的页号
commds存放的是这一条指令对应的页号
MemoryCell memory[MEM_PAHE_NUM]; //内存块
memory就是内存了,也就是分配给一作业的内存块,按照本题目就是大小是4个页框。
vector order_commd;
这个存放的是按照题目需求生成的随机指令序列
vector order_page;
这个存放的是按照指令序列转化而成的页号序列。
先上需求:
通过随机数产生一个指令序列,共 320 条指令。
① 50%的指令是顺序执行的;
② 25%的指令是均匀分布在前地址部分;
③ 25%的指令是均匀分布在后地址部分;
具体的实施方法是:
① 在[0, 319]的指令地址之间随机选取一起点 m;
② 顺序执行一条指令,即执行地址为 m+1 的指令;
③ 在前地址[0, m+1]中随机选取一条指令并执行,该指令的地址为 m1;
④ 顺序执行一条指令,其地址为 m1+1;32
⑤ 在后地址[m1+2, 319]中随机选取一条指令并执行;
⑥ 重复上述步骤①~⑤,直到执行 320 条指令。
这是指导书给的实现方法
实际代码实现时,还要注意边界问题,就是m + 1的时候会不会超过319,需要特判,其余按照题目所说直接实现。最后将指令序列再转化为页号序列就行了
核心代码如下:
void createArray()
{
srand((unsigned)time(NULL));
int commd = 0;
while(commd < COMMD_NUM)
{
//范围是[0,319]
int m = rand()%COMMD_NUM;
order_commd.push_back(m);
commd++;
if(commd >= COMMD_NUM)
break;
if(m == COMMD_NUM-1)
continue;
order_commd.push_back(m+1);
commd++;
if(commd >= COMMD_NUM)
break;
//范围是[0,m+1]
m = rand()% (m+2);
order_commd.push_back(m);
commd++;
if(commd >= COMMD_NUM)
break;
if(m == COMMD_NUM-1)
continue;
order_commd.push_back(m+1);
commd++;
if(commd >= COMMD_NUM)
break;
//范围是[m+2,319]
m = rand()% (COMMD_NUM -m -2) + m+2;
order_commd.push_back(m);
commd++;
if(commd >= COMMD_NUM)
break;
}
//将指令序列转化为页号序列
for(int i=0;i
最简单的就是FIFO的实现
如果页框没满(不足4个)就直接按顺序排下来,如果满了,就将第一份踢出,然后将新页号插到尾部,因为用的数组,替换就用的是后一个覆盖前一个,如果是链表的数据结构的话,就直接修改指针就行了。
核心代码:
for(int i=0;i
然后就是LRU的模拟
LRU的实现也简单,只需要一直更新时间戳就行了,如果内存没满,就直接插入尾部,如果内存满了,就找出时间戳最早的,然后把它覆盖就行了。时间戳我实现的是用的页号的顺序数组下标索引,就是0-319,置换的时候将最小的换出去就行了。
核心代码:
for(int i=0;i memory[j].time)
{
minn = j;
}
}
memory[minn].time = i;
memory[minn].index = order_page[i];
}
}
}
最后是OPT模拟
OPT是最佳适配算法,置换时淘汰“未来不再使用的”或“在离当前最远位置上出现的”页面。由于实际中是不可能提前知道未来所需的页号,所以也只是理论上的最优算法。我的实现思路是每次置换出现最远的。
如果内存没满,就按照顺序直接插入尾部,如果内存页框满了,就置换,置换的时候依次扫描页框中的页号,看它在页号序列中下一次出现的位置,用一个数组记录下来,数组初始化的时候,赋最大值,意义是如果扫描的时候没找到下一次出现,则距离最大。将内存4个页框都找完之后,选择其中“下一次出现最远的”一个,置换掉就行了。
源码参考:
for(int i=0;i
五次结果如上,很有意思的结果,FIFO和LRU的缺页情况相差不大,也有几次两者缺页率相同,甚至偶尔FIFO的缺页率低于LRU。
仔细分析代码,应该不是代码逻辑错误,我想可能还是指令数量太少,页框比较小,我几次调大内存页框数和指令数,确实有所改善,当然OPT的缺页率永远是最低的,也有一部分指导意义。
在学习操作系统的时候,我也曾用C模拟过这几个算法,主要模拟的是FIFO,LRU和Clock算法,不用当时的结果更加离谱,多次改变数据之后仍不符合预期,后来和同学老师讨论之后得出的结论是我的页号序列没有体现程序局部性,我用Python生成了1百万个随机数到文件中,然后C程序读取文件测试,最后不论如何测试几种算法的缺页率都很相近。这次用指导书上的方法生成的页号序列比较有参考意义的,结果比较符合预期,尤其是LRU算法,本实验收获很多。=w=
#include
#include
#include
#include
#include
#define MEM_PAHE_NUM 4
#define COMMD_NUM 320
#define PAGE_COMMD 10
#define MAX_FAR 1000000000
using namespace std;
struct MemoryCell
{
int index;//页号
int time;//时间戳
};
int commds[COMMD_NUM]; //存放的是每一条指令的页号
MemoryCell memory[MEM_PAHE_NUM]; //内存块
vector order_commd;
vector order_page;
void initPage(); //初始化页表
void createArray(); //生成序列
double FIFO(); //用FIFO置换算法
double LRU(); //用LRU置换算法
double OPT(); //用OPT置换算法
int main()
{
initPage();
createArray();
double fifo = FIFO();
double lru = LRU();
double opt = OPT();
printf("fifo = %f lru = %f opt = %f\n",fifo,lru,opt);
return 0;
}
void initPage()
{
//现在开始给每个页分配指令
int page_index=0;
for(int i=0;i= COMMD_NUM)
break;
if(m == COMMD_NUM-1)
continue;
order_commd.push_back(m+1);
commd++;
if(commd >= COMMD_NUM)
break;
//范围是[0,m+1]
m = rand()% (m+2);
order_commd.push_back(m);
commd++;
if(commd >= COMMD_NUM)
break;
if(m == COMMD_NUM-1)
continue;
order_commd.push_back(m+1);
commd++;
if(commd >= COMMD_NUM)
break;
//范围是[m+2,319]
m = rand()% (COMMD_NUM -m -2) + m+2;
order_commd.push_back(m);
commd++;
if(commd >= COMMD_NUM)
break;
}
//将指令序列转化为页号序列
for(int i=0;i memory[j].time)
{
minn = j;
}
}
memory[minn].time = i;
memory[minn].index = order_page[i];
}
}
for(int j=0;j