源代码在文章最后面
创作不易,喜欢的点个赞
实验目的
通过对页面、页表、地址转换和页面置换过程的模拟,加深对虚拟页式内存管理系统的页面置换原理和实现过程的理解。
总体设计
背景知识:首先要明白什么是页面置换,页面置换的目的是什么,需要调入新页面时,选择内存中哪个物理页面被置换,称为置换策略。页面置换算法的目标:
把未来不再使用的或短期内较少使用的页面调出,通常应在局部性原理指导下依据过去的统计数据进行预测,减少缺页次数。
涉及的算法原理:
FIFO算法:置换时淘汰最先进入内存的页面。
OPT算法:置换时淘汰未来不再使用或离当前最远位置上出现的页面。
LRU算法:置换时淘汰最近一段时间最久没有使用的页面,即选择上次使用距当前最远的页面淘汰。
Clock算法:Clock算法的主要原理是将页面按照使用情况分为两类:被访问过的和未被访问过的。当要替换一个页面时,Clock算法会先检查当前指针指向的页面,如果该页面被访问过,则将它的访问位重新设置为0,然后将指针下移;如果该页面未被访问过,则将该页面替换出去,并将指针指向下一个页面。如果经过一次遍历后,没有找到未被访问过的页面,则再进行一次遍历,但此次遍历时不再按照访问位进行判断,直接替换下一个页面。
为了体现程序的局部性原理,需要随机生成一个指令序列,根据指导书要求,生成随机序列应该这样生成:
① 50%的指令是顺序执行的;
② 25%的指令是均匀分布在前地址部分;
③ 25%的指令是均匀分布在后地址部分;
模块设计:
该实验主要分为三个部分:第一是数据结构的设计,如何处理页框和指令的数据类型;第二就是指令的生成,如何生成一个体现局部性原理的随机序列;第三就是实现各个算法。
详细设计
设计的数据结构:
页框的数据结构:
struct Memery {
int indexs;//页号
int time;//时间戳
int a;//Clock算法的标志位
};
vector<int>order:用来记录生成的随机指令序列;
vector<int>orderpage:存放将指令序列转化为页号序列;
Memery memery[PageKuang]:内存块,结构体数组,按照此实验大小就是4个页框。
指令序列的生成:
① 在[0, 319]的指令地址之间随机选取一起点 m;
② 顺序执行一条指令,即执行地址为 m+1 的指令;
③ 在前地址[0, m+1]中随机选取一条指令并执行,该指令的地址为 m1;
④ 顺序执行一条指令,其地址为 m1+1;
⑤ 在后地址[m1+2, 319]中随机选取一条指令并执行;
⑥ 重复上述步骤①~⑤,直到执行 320 条指令。
关键代码如下:
srand((unsigned)time(NULL));
int idx=0;
while(idx<N) {
int m=rand()%N;//在[0,319]随机选取一点
order.push_back(m+1);
idx++;
if(idx>=N)break;
int m1=rand()%(m+2);//在[0,m+1]随机选取一点
order.push_back(m1);
idx++;
if(idx>=N)break;
if(m1==N-1)continue;
order.push_back(m1+1);
idx++;
if(idx>=N)break;
m=rand()%(N-m1-2)+m1+2;
order.push_back(m);
idx++;
if(idx>=N)break;
}
for(int i=0; i<N; i++) {
orderpage.push_back(order[i]/10);//将指令序列转化为页号序列
// orderpage.push_back(demo[i]);
}
FIFO算法的实现:如果页框未满,则直接按顺序放进去,如果页框满了,就把第一个置换出去,用数组来实现的话就是直接用后一个覆盖前一个。关键代码如下:
int error=0;
int memerypagenum=0;
for(int i=0; i<orderpage.size(); i++) {
int flag=0;
for(int j=0; j<memerypagenum; j++) {
if(memery[j].indexs==orderpage[i]) {
flag=1;
break;
}
}
if(!flag) {
error++;
if(memerypagenum<PageKuang) { //页框未满
memery[memerypagenum++].indexs=orderpage[i];
} else { //页框满了要置换
// error++;
for(int j=1; j<memerypagenum; j++) {
memery[j-1]=memery[j];
}
memery[memerypagenum-1].indexs=orderpage[i];
}
}
LRU算法的实现:只需要一直更新时间戳即可,如果页框没满,直接在尾部插进去,如果满了,就置换出时间戳最早的,时间戳用循环下标实现,为0-319。关键代码如下:
if(memerypagenum<PageKuang) {
memery[memerypagenum].time=i;//用来表示当前的时间戳
memery[memerypagenum++].indexs=orderpage[i];//记录下页号
} else {
for(int j=0; j<memerypagenum; j++) {
if(memery[mins].time>memery[j].time) {
mins=j;//找出最靠前的时间戳
}
}
memery[mins].time=i;
memery[mins].indexs=orderpage[i];//完成置换操作
}
}
OPT算法的实现:我的思路是用一个dist数组来记录后面的指令序列离当前页框中存在的序列的距离,找出最远的那个,将其替换即可,如果后面的指令没有一个与页框指令相同,则随便替换一个即可。我实现的是直接替换第一个。关键代码如下:
memset(dist,0x3f,sizeof dist);//初始为无穷大
for(int j=0; j<memerypagenum; j++) {
for(int k=i+1; k<orderpage.size(); k++) {
if(memery[j].indexs==orderpage[k]) {
dist[j]=k;
break;
}
}
}
for(int j=0; j<memerypagenum; j++) {
if(dist[maxs]<dist[j]) {
maxs=j;
}
}
memery[maxs].indexs=orderpage[i];
}
Clock算法的原理:我的思路是用一个全局变量xiabiao来标志指针的移动,用一个while死循环来查找。这个标志每次对页框数取余,如果标志符a为0则直接替换,将新添加的指令的标识符a改为1,标志xiabiao++;如果指令的标识符a=1则更改a=0;xiabiao++移动指针到下一个。
源代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<time.h>
#include<cstdlib>
#include<stdio.h>
using namespace std;
const int N=320;
const int PageNum=10;
const int PageKuang=4;
vector<int>order;
vector<int>orderpage;
struct Memery {
int indexs;
int time;
int a;
};
//int demo[12]={2,3,2,1,5,2,4,5,3,2,5,2};
//int demo[20]={7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1};
Memery memery[PageKuang];
int xiabiao;
void initorder() {
srand((unsigned)time(NULL));
int idx=0;
while(idx<N) {
int m=rand()%N;//在[0,319]随机选取一点
// order.push_back(m);
// idx++;
// if(idx>=N)break;
if(m==N-1)continue;
order.push_back(m+1);
idx++;
if(idx>=N)break;
int m1=rand()%(m+2);//在[0,m+1]随机选取一点
order.push_back(m1);
idx++;
if(idx>=N)break;
if(m1==N-1)continue;
order.push_back(m1+1);
idx++;
if(idx>=N)break;
m=rand()%(N-m1-2)+m1+2;
order.push_back(m);
idx++;
if(idx>=N)break;
}
for(int i=0; i<N; i++) {
orderpage.push_back(order[i]/10);
// orderpage.push_back(demo[i]);
}
}
void fifo() {
int error=0;
int memerypagenum=0;
for(int i=0; i<orderpage.size(); i++) {
int flag=0;
for(int j=0; j<memerypagenum; j++) {
if(memery[j].indexs==orderpage[i]) {
flag=1;
break;
}
}
if(!flag) {
error++;
if(memerypagenum<PageKuang) { //页框未满
memery[memerypagenum++].indexs=orderpage[i];
} else { //页框满了要置换
// error++;
for(int j=1; j<memerypagenum; j++) {
memery[j-1]=memery[j];
}
memery[memerypagenum-1].indexs=orderpage[i];
}
}
for(int j=0; j<memerypagenum; j++) {
cout<<memery[j].indexs<<" ";
}
if(!flag)cout<<"F";
cout<<endl;
}
double ans=(double)(error*1.0/N);
cout<<"缺页次数:"<<error<<endl;
cout<<"fifo缺页率:";
printf("%.6lf\n",ans);
}
void LRU() {
int error=0;
int memerypagenum=0;
for(int i=0; i<orderpage.size(); i++) {
int flag=0;
for(int j=0; j<memerypagenum; j++) {
if(memery[j].indexs==orderpage[i]) {
flag=1;
memery[j].time=i;//更新当前指令的时间戳
break;
}
}
if(!flag) {
error++;
int mins=0;
if(memerypagenum<PageKuang) {
memery[memerypagenum].time=i;//用来表示当前的时间戳
memery[memerypagenum++].indexs=orderpage[i];//记录下页号
} else {
for(int j=0; j<memerypagenum; j++) {
if(memery[mins].time>memery[j].time) {
mins=j;//找出最靠前的时间戳
}
}
memery[mins].time=i;
memery[mins].indexs=orderpage[i];//完成置换操作
}
}
for(int j=0; j<memerypagenum; j++) {
cout<<memery[j].indexs<<" ";
}
if(!flag)cout<<"F";
cout<<endl;
}
double ans;
ans=(double)(error*1.0/N);
cout<<"缺页次数:"<<error<<endl;
cout<<"LRU缺页率:";
printf("%.6lf\n",ans);
}
void OPT() {
int error=0;
int memerypagenum=0;
for(int i=0; i<orderpage.size(); i++) {
int flag=0;
for(int j=0; j<memerypagenum; j++) {//命中
if(memery[j].indexs==orderpage[i]) {
flag=1;
break;
}
}
if(!flag) {//未命中
error++;
if(memerypagenum<PageKuang) {
memery[memerypagenum++].indexs=orderpage[i];//页框未满
} else { //需要置换
int dist[PageKuang];//用于保存等于页框指令的指令距离页框指令的远近
int maxs=0;
memset(dist,0x3f,sizeof dist);//初始为无穷大
for(int j=0; j<memerypagenum; j++) {
for(int k=i+1; k<orderpage.size(); k++) {
if(memery[j].indexs==orderpage[k]) {
dist[j]=k;
break;
}
}
}
for(int j=0; j<memerypagenum; j++) {
if(dist[maxs]<dist[j]) {
maxs=j;
}
}
memery[maxs].indexs=orderpage[i];
}
}
for(int j=0; j<memerypagenum; j++)
cout<<memery[j].indexs<<" ";
if(!flag)cout<<"F";
cout<<endl;
}
cout<<"缺页次数:"<<error<<endl;
cout<<"OPT的缺页率:";
double ans=(double)(error*1.0/N);
printf("%.6lf\n",ans);
}
void Clock() {
int error=0;
int memerypagenum=0;
for(int i=0; i<orderpage.size(); i++) {
int flag=0;
for(int j=0; j<memerypagenum; j++) {
if(memery[j].indexs==orderpage[i]) {
memery[j].a=1;
flag=1;
break;
}
}
if(!flag) {
error++;
if(memerypagenum<PageKuang) { //页框未满
memery[memerypagenum].indexs=orderpage[i];
memery[memerypagenum++].a=1;
} else { //需要使用置换
while(1) {
xiabiao=xiabiao%PageKuang;
if(memery[xiabiao].a==0&&xiabiao<PageKuang) {
memery[xiabiao].indexs=orderpage[i];
memery[xiabiao].a=1;
xiabiao++;
break;
} else if(memery[xiabiao].a==1) {
memery[xiabiao].a=0;
xiabiao++;
}
}
}
}
for(int j=0; j<memerypagenum; j++)
cout<<memery[j].indexs<<" ";
if(!flag)cout<<"F";
cout<<endl;
}
cout<<"缺页次数:"<<error<<endl;
cout<<"Clock的缺页率:";
double ans=(double)(error*1.0/N);
printf("%.6lf\n",ans);
}
int main() {
initorder();
fifo();
LRU();
OPT();
Clock();
return 0;
}