前言

课程设计开始了,实验很有意思,写博客总结学到的知识
白嫖容易,创作不易,学到东西才是真
本文原创,创作不易,转载请注明!!!
本文链接
个人博客: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<int> order_commd;

这个存放的是按照题目需求生成的随机指令序列

vector<int> 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<order_commd.size();i++){order_page.push_back(commds[order_commd[i]]);}
}

第三部分 置换算法的实现

FIFO

最简单的就是FIFO的实现
如果页框没满(不足4个)就直接按顺序排下来,如果满了,就将第一份踢出,然后将新页号插到尾部,因为用的数组,替换就用的是后一个覆盖前一个,如果是链表的数据结构的话,就直接修改指针就行了。
核心代码:

for(int i=0;i<order_page.size();i++){bool flag =0;for(int j=0;j<memory_page_num;j++){if(memory[j].index == order_page[i]){flag = true;//找到了break;}}if(!flag)   //没找到,发生缺页{err++;//缺页统计if(memory_page_num < MEM_PAHE_NUM) //没满{memory[memory_page_num++].index = order_page[i];}else    //利用置换算法开始置换{for(int j=1;j<memory_page_num;j++){memory[j-1] = memory[j];//将第一个置换出去}memory[memory_page_num-1].index=order_page[i];}}
}

LRU

然后就是LRU的模拟
LRU的实现也简单,只需要一直更新时间戳就行了,如果内存没满,就直接插入尾部,如果内存满了,就找出时间戳最早的,然后把它覆盖就行了。时间戳我实现的是用的页号的顺序数组下标索引,就是0-319,置换的时候将最小的换出去就行了。
核心代码:

for(int i=0;i<order_page.size();i++){bool flag =0;for(int j=0;j<memory_page_num;j++){if(memory[j].index == order_page[i]){flag = true;memory[j].time = i; //更新时间戳break;}}if(!flag)   //没找到,发生缺页{int minn=0;//标记最小的err++;if(memory_page_num < MEM_PAHE_NUM){memory[memory_page_num].time = i; //留下时间戳memory[memory_page_num++].index = order_page[i];}else    //利用置换算法开始置换{for(int j=0;j<memory_page_num;j++){if(memory[minn].time > memory[j].time){minn = j;}}memory[minn].time = i;memory[minn].index = order_page[i];}}
}

OPT

最后是OPT模拟
OPT是最佳适配算法,置换时淘汰“未来不再使用的”或“在离当前最远位置上出现的”页面。由于实际中是不可能提前知道未来所需的页号,所以也只是理论上的最优算法。我的实现思路是每次置换出现最远的。
如果内存没满,就按照顺序直接插入尾部,如果内存页框满了,就置换,置换的时候依次扫描页框中的页号,看它在页号序列中下一次出现的位置,用一个数组记录下来,数组初始化的时候,赋最大值,意义是如果扫描的时候没找到下一次出现,则距离最大。将内存4个页框都找完之后,选择其中“下一次出现最远的”一个,置换掉就行了。
源码参考:

for(int i=0;i<order_page.size();i++){bool flag =0;for(int j=0;j<memory_page_num;j++){if(memory[j].index == order_page[i]){flag = true;break;}}if(!flag)   //没找到,发生缺页{err++;if(memory_page_num < MEM_PAHE_NUM){memory[memory_page_num++].index = order_page[i];}else    //利用置换算法开始置换{int far[MEM_PAHE_NUM] ;//存储距离int furthest = 0;//找最远的位置;for(int j=0;j<MEM_PAHE_NUM;j++) //初始化为最大值far[j] = MAX_FAR;for(int j=0;j<memory_page_num;j++){for(int k=i+1;k<order_page.size();k++){if(memory[j].index == order_page[k]) //未来出现的位置far[j] = k;}}for(int j=0;j<memory_page_num;j++) //找最远的位置if(far[furthest] < far[j])furthest = j;//找到之后,置换memory[furthest].index = order_page[i];}}}

实验结果与分析





五次结果如上,很有意思的结果,FIFO和LRU的缺页情况相差不大,也有几次两者缺页率相同,甚至偶尔FIFO的缺页率低于LRU。
仔细分析代码,应该不是代码逻辑错误,我想可能还是指令数量太少,页框比较小,我几次调大内存页框数和指令数,确实有所改善,当然OPT的缺页率永远是最低的,也有一部分指导意义。

小结与心得体会

在学习操作系统的时候,我也曾用C模拟过这几个算法,主要模拟的是FIFO,LRU和Clock算法,不用当时的结果更加离谱,多次改变数据之后仍不符合预期,后来和同学老师讨论之后得出的结论是我的页号序列没有体现程序局部性,我用Python生成了1百万个随机数到文件中,然后C程序读取文件测试,最后不论如何测试几种算法的缺页率都很相近。这次用指导书上的方法生成的页号序列比较有参考意义的,结果比较符合预期,尤其是LRU算法,本实验收获很多。=w=

源代码

#include <iostream>
#include <cstdio>
#include <time.h>
#include <cstdlib>
#include <vector>#define MEM_PAHE_NUM 4
#define COMMD_NUM 320
#define PAGE_COMMD 10
#define MAX_FAR 1000000000using namespace std;struct MemoryCell
{int index;//页号int time;//时间戳
};int commds[COMMD_NUM];    //存放的是每一条指令的页号
MemoryCell memory[MEM_PAHE_NUM];  //内存块
vector<int> order_commd;
vector<int> 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;i++){commds[i]=page_index;if((i+1) % PAGE_COMMD ==0){page_index++;}}//    for(int i=0;i<COMMD_NUM;i++)
//    {
//        printf("%d ",commds[i]);
//        if((i+1) % PAGE_COMMD ==0)
//        {
//            printf("\n");
//        }
//    }
}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<order_commd.size();i++){order_page.push_back(commds[order_commd[i]]);}//    printf("order_commd_size = %d\n",order_commd.size());
//    for(int i=0;i<order_commd.size();i++)
//    {
//        printf("%d ",order_commd[i]);
//    }//    printf("order_page_size = %d\n",order_page.size());
//    for(int i=0;i<order_page.size();i++)
//    {
//        printf("%d ",order_page[i]);
//    }
}double FIFO()
{int memory_page_num = 0;int err = 0;for(int i=0;i<order_page.size();i++){bool flag =0;for(int j=0;j<memory_page_num;j++){if(memory[j].index == order_page[i]){flag = true;break;}}if(!flag)   //没找到,发生缺页{err++;if(memory_page_num < MEM_PAHE_NUM){memory[memory_page_num++].index = order_page[i];}else    //利用置换算法开始置换{for(int j=1;j<memory_page_num;j++){memory[j-1] = memory[j];//将第一个置换出去}memory[memory_page_num-1].index=order_page[i];}}for(int j=0;j<memory_page_num;j++){printf("%d",memory[j].index);(memory[j].index == order_page[i])?printf("* "):printf(" ");}if(!flag) printf("F");printf("\n");}printf("FIFO err =%d\n",err);return (double)err / COMMD_NUM;
}double LRU()
{int memory_page_num = 0;int err = 0;for(int i=0;i<order_page.size();i++){bool flag =0;for(int j=0;j<memory_page_num;j++){if(memory[j].index == order_page[i]){flag = true;memory[j].time = i; //更新时间戳break;}}if(!flag)   //没找到,发生缺页{int minn=0;//标记最小的err++;if(memory_page_num < MEM_PAHE_NUM){memory[memory_page_num].time = i; //留下时间戳memory[memory_page_num++].index = order_page[i];}else    //利用置换算法开始置换{for(int j=0;j<memory_page_num;j++){if(memory[minn].time > memory[j].time){minn = j;}}memory[minn].time = i;memory[minn].index = order_page[i];}}for(int j=0;j<memory_page_num;j++){printf("%d",memory[j].index);(memory[j].index == order_page[i])?printf("* "):printf(" ");}if(!flag) printf("F");printf("\n");}printf("LRU err =%d\n",err);return (double)err / COMMD_NUM;
}double OPT()
{int memory_page_num = 0;int err = 0;for(int i=0;i<order_page.size();i++){bool flag =0;for(int j=0;j<memory_page_num;j++){if(memory[j].index == order_page[i]){flag = true;break;}}if(!flag)   //没找到,发生缺页{err++;if(memory_page_num < MEM_PAHE_NUM){memory[memory_page_num++].index = order_page[i];}else    //利用置换算法开始置换{int far[MEM_PAHE_NUM] ;//存储距离int furthest = 0;//找最远的位置;for(int j=0;j<MEM_PAHE_NUM;j++) //初始化为最大值far[j] = MAX_FAR;for(int j=0;j<memory_page_num;j++){for(int k=i+1;k<order_page.size();k++){if(memory[j].index == order_page[k]) //未来出现的位置far[j] = k;}}for(int j=0;j<memory_page_num;j++) //找最远的位置if(far[furthest] < far[j])furthest = j;//找到之后,置换memory[furthest].index = order_page[i];}}for(int j=0;j<memory_page_num;j++){printf("%d",memory[j].index);(memory[j].index == order_page[i])?printf("* "):printf(" ");}if(!flag) printf("F");printf("\n");}printf("OPT err =%d\n",err);return (double)err / COMMD_NUM;
}

操作系统课设之虚拟内存页面置换算法的模拟与实现相关推荐

  1. 南京邮电大学操作系统实验三:虚拟内存页面置换算法

    实验内容 使用数组存储一组页面请求,页面请求的数量要50个以上,访问的页面号可以用随机数生成(0~20): (1)设置为分配给进程的页框数(假定是5),使用LRU算法,模拟完成全部的页面请求,最后输出 ...

  2. C++实现虚拟内存页面置换算法(FIFO, OPT, LRU)

    虚拟内存页面置换算法(FIFO, OPT, LRU) 0x01 FIFO 置换策略:置换掉先来的页面(FIFO队列首元素) 优点: 简单易理解且易实现 缺点: 性能不理想,会发生Belady异常(页框 ...

  3. 【清华大学】操作系统 陈渝——Part6 全局页面置换算法

    [清华大学]操作系统 陈渝--Part6 局部页面置换算法 6.8 局部页面替换算法的问题,工作集模型 局部页面替换算法的问题 工作集模型 6.9 全局页面置换算法 1. 工作集页置换算法 2. 可变 ...

  4. 操作系统实验:页面置换算法的模拟实现及命中率对比(学习笔记)

    操作系统实验:页面置换算法的模拟实现及命中率对比(学习笔记) 题目要求 输入要求 输出要求 编程平台 实验成果 开始模拟 错误输入 退出程序 代码实现 抽象数据类型定义 指令地址流生成 指令地址流到页 ...

  5. 请求页式存储管理中页面置换算法的模拟设计_操作系统-存储管理与文件管理-笔记...

    存储管理 一.页式存储 将各进程的虚拟空间划分成若干个长度相等的页,页式管理把内存空间按页的大小划分成片或者页面,然后把页式虚拟地址与内存地址建立一一对应页表,并用相应的硬件地址变换机构,来解决离散地 ...

  6. 先进先出页面置换算法的模拟(c++实现)

    实验要求 1)设计模拟实现OPT.FIFO和LRU页面置换算法中的任意一种. OPT算法:需要发生页面置换时,算法总是选择在将来最不可能访问的页面进行置换. FIFO算法:算法总是选择在队列中等待时间 ...

  7. 操作系统课设之简单 shell 命令行解释器的设计与实现

    前言 课程设计开始了,实验很有意思,写博客总结学到的知识 白嫖容易,创作不易,学到东西才是真 本文原创,创作不易,转载请注明!!! 本文链接 个人博客:https://ronglin.fun/arch ...

  8. 操作系统课设之基于信号量机制的并发程序设计

    前言 课程设计开始了,实验很有意思,写博客总结学到的知识 白嫖容易,创作不易,学到东西才是真 本文原创,创作不易,转载请注明!!! 本文链接 个人博客:https://ronglin.fun/arch ...

  9. 操作系统课设之内存管理

    前言 课程设计开始了,实验很有意思,写博客总结学到的知识 白嫖容易,创作不易,学到东西才是真 本文原创,创作不易,转载请注明!!! 本文链接 个人博客:https://ronglin.fun/arch ...

最新文章

  1. 【仿汽车之家】价格区间选择控件
  2. python从入门到精通视频教程百度云-python从入门到精通视频教程百度云资源
  3. RTP与RTSP的区别
  4. 洛谷P1202 [USACO1.1]黑色星期五Friday the Thirteenth
  5. pb 执行存储过程带参数_数据库存储过程
  6. 在微信小程序中使用“随机键盘”
  7. tmux颜色高亮跟vim不一致的情况
  8. linux mysql 5.6.23_mysql 5.6.23 的安装
  9. 【Django】Django Debug Toolbar调试工具配置
  10. 如何在Linux开启HTTP服务,小技巧:如何快速开启一个静态 HTTP 服务?
  11. POJ 1155 TELE【树形DP】
  12. Qt实战案例(18)——Qt位置相关函数汇总实例
  13. Kafka的Topic删不掉
  14. Python制作个税计算器
  15. java中的锁池和等待池是什么_线程的几个状态及方法,等待池和锁池的理解
  16. plt_iris Matplotlib画图参数 Numpy 莺尾花演示
  17. vijos 1282128312841285 佳佳的魔法照片/魔法药水/魔杖/魔法阵
  18. Infor SyteLine ERP 客户端使用设置
  19. Oracle数据库数据查询语句示例(包含大部分常用语句)
  20. 笔记:Stack overflow栈溢出

热门文章

  1. Spring Cloud 配置中心客户端读取配置
  2. 京东云Ubuntu下安装mysql
  3. docker探索-windows10 docker 使用 mysql(二)
  4. Struts2与Struts1的区别
  5. Android官方开发文档Training系列课程中文版:电池续航时间优化之检查、检测网络连接状态...
  6. python核心编程笔记chapter 3
  7. sed,awk,grep,trap,trap,cut,tr,curl,find
  8. Object类的用法(一)
  9. 这让全场的chinaakd
  10. 面试刷题必看!Python中的5大排序算法及其实现代码