OS 请求调页存储管理方式的FIFO、LRU、OPT、LFU置换算法模拟

1.设计目的

通过对页面、页表、地址转换和页面置换过程的模拟,加深对请求调页系统的原理和实现过程的理解。

2.设计内容

  1)假设每个页面中可存放10条指令,分配给作业的内存块数为4。

  2)用c语言模拟一个作业的执行过程,该作业共有320条指令,即它的地址空间为32页,目前它的所有页都还未调入内存。在模拟过程中,如果所访问的指令已在内存,则显示其物理地址,并转下一条指令。如果所访问的指令还未装入内存,则发生缺页,此时需记录缺页的次数,并将相应页调入内存。如果4个内存块均已装入该作业,则需进行页面置换,最后显示其物理地址,并转下一条指令。

在所有320指令执行完毕后,请计算并显示作业运行过程中发生的缺页率。

  3)置换算法:

1、采用先进先出(FIFO)置换算法。

2、最近最久未使用(LRU)算法。

3、最佳置换(OPT)算法。

4、最少访问(LFU)算法。

提示:

(1)通过随机数产生一个指令序列,共320条指令。指令的地址按下述原则生成:

① 50%的指令是顺序执行的;

  ② 25%的指令是均匀分布在前地址部分;

③ 25%的指令是均匀分布在后地址部分;

具体的实施方法是:

① 在[0,319]的指令地址之间随机选取一起点m;

② 顺序执行一条指令,即执行地址为m+1的指令;

③ 在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m

④ 顺序执行一条指令,其地址为m+1的指令;

⑤ 在后地址[m+2,319]中随机选取一条指令并执行;

⑥ 重复上述步骤①~⑤,直到执行320次指令。

(2)将指令序列变换为页地址流

① 设页面大小为1K;

② 用户内存容量为4页到32页;

③ 用户虚存容里为32K。

在用户虚存中,按每K存放10条指令排列虚存地址,即320条指令在虚存中的存放方式为:

第0条~第9条指令为第0页(对应虚存地址为[0,9]);

第10条~第19条指令为第1页(对应虚存地址为[10,19]);

……

……

第310条~第319条指令为第31页(对应虚存地址为[310,319])。

按以上方式,用户指令可组成32页。

(3)计算先进先出(FIFO)算法在不同内存容量下的命中率。

 

其中,命中率=1-页面失效次数/页地址流长度


  • 采用先进先出(FIFO)置换算法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<ctime>
#include<cstring>
#include<cstdlib>
using namespace std;
struct node{
    int i,j;//进入内存的页面数和页内地址
    int p;//页面值
    int k;//记录页面在内存中中的位置1~4
};
struct NN{
    int flag;//表示是否存在在内存中
    int id;//在内存中的位置1~4
};

int page[33][11];//保存页面和指令
int qk=0,sss=0;//用于记录缺页的次数
queue<node> q;
int hashmap[330];//一共用320条指令

double random();//生成[0,1]之间的均匀数字
int random(int m);//生成[0,m-1]之间的均匀随机数
void Init(int r);//定义初始化函数,初始值为r
void Init_Page();//初始化页面
void Show();//显示页面信息
int Address(int i,int j);//计算每个页面对应的地址
void Oper_FIFO(int n);//FIFO操作算法
void Print();

int main()
{
    freopen("input.txt","r",stdin);
    freopen("FIFO.txt","w",stdout);
    Init(6);
    printf("生成的随机数\n");
    Show();
    Init_Page();
    printf("对应的调入页面\n");
    Show();
    Oper_FIFO(4);
    Print();
	return 0;
}
double random(){//生成[0,1]之间的均匀数字
    return (double) rand() / RAND_MAX;
}

int random(int m){//生成[0,m-1]之间的均匀随机数
    return (int) (random()*(m-1)+0.5);
}
int Address(int i,int j){//计算每个页面对应的地址
    return i*10+j;
}

void Init(int r){//初始化函数,初始化指令
    srand(time(NULL));
    int ok=1,j=0;
    for(int i=0;i<32;){
        if(j==10){
            i++; j=0;
            if(i>=32) break;
        }
        if(ok==1){
            r=random(320);
            page[i][j++]=r;
            page[i][j++]=r+1;
            ok=2;//标记进入第二个随机数
            continue;
        }
        if(ok==2){
            int k=(random(r+1));//1-m+1随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=3;//标记下次进入第二个随机数
            continue;
        }
        if(ok==3){
            int k=(r+2)+(random(320-r-2));//在m+2和320之间随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=1;//下次进入标记进入第一个随机数
            continue;
        }
    }
}
void Init_Page(){//初始化页面
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            page[i][j]=page[i][j]/10;
        }
    }
}

void Oper_FIFO(int n){//操作函数,先进先出
    int s=0;//内存的首指
    memset(hashmap,0,sizeof(hashmap));//用于记录当前页面是否在内存中,0:不在,1:在
    for(int i=0;i<32;i++){//下面是有320条指令的作业的运行情况
        for(int j=0;j<10;j++){
            if(hashmap[page[i][j]]==1){//页面在内存中
                printf("当前访问页面在内存中,当前页面的地址为%d\n",Address(i,j));
                sss++;
            }
            else{//当前页面不在内存中,增加缺页次数,并调入内存
                qk++;//增加缺页次数
                node temp,temp1;
                temp.i=i;
                temp.j=j;
                temp.p=page[i][j];

                if(q.size()<n){//内存使用小于4,直接调入
                    printf("页面不存在,有空的内存空间,直接调入。\n");
                    temp.k=s%4+1;
                    hashmap[page[i][j]]=1;

                    q.push(temp);
                    //记录此页已在内存中
                    ++s;
                }
                if(q.size()==n){//内存已占用4,按先进先出移除一个页面
                    temp1=q.front();//取出队首元素
                    q.pop();
                    printf("页面不存在,内存空间已满,按算法移除页面为:%d,其地址为:%d,它占用的内存块为:%d\n",temp1.p,Address(temp1.i,temp1.j),temp1.k);
                    temp.k=temp1.k;
                    hashmap[temp1.p]=0;//移除的页面变为未存在
                    q.push(temp);
                    hashmap[page[i][j]]=1;//进入的页面表示为存在
                }
            }
        }
    }
}

void Show(){
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            printf("%d ",page[i][j]);
        }
        printf("\n");
    }
}

void Print(){
    printf("缺页次数为:%d  匹配成功次数:%d\n",qk,sss);
    printf("缺页率为:%.3lf%%\n",1.0*qk/320*100);
}
  • 最近最久未使用(LRU)算法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<ctime>
#include<cstring>
#include<cstdlib>
using namespace std;
struct node{
    int i,j;//进入内存的页面数和页内地址
    int p;//页面值
    int k;//记录页面在内存中中的位置1~4
};
struct NN{
    int flag;//表示是否存在在内存中
    int id;//在内存中的位置1~4
};

int page[33][11];//保存页面和指令
int qk=0;//用于记录缺页的次数
node q[136];//定义内存块的个数
clock_t hashmap[330];//一共用320条指令

double random();//生成[0,1]之间的均匀数字
int random(int m);//生成[0,m-1]之间的均匀随机数
void Init(int r);//定义初始化函数,初始值为r
void Init_Page();//定义page初始化函数
void Show();//显示页面信息
int Address(int i,int j);//计算每个页面对应的地址
void Oper_LRU(int n);//LRU操作算法
void Print();
int cmp(node a,node b);//定义比较函数

int main()
{
    freopen("input14.txt","r",stdin);
    freopen("LRU.txt","w",stdout);
    int n;
    Init(56);
    Init_Page();
    printf("调入页面:\n");
    Show();s
    scanf("%d",&n);
    Oper_LRU(n);
    Print();
	return 0;
}
double random(){//生成[0,1]之间的均匀数字
    return (double) rand() / RAND_MAX;
}

int random(int m){//生成[0,m-1]之间的均匀随机数
    return (int) (random()*(m-1)+0.5);
}
int Address(int i,int j){//计算每个页面对应的地址
    return i*10+j;
}

void Init(int r){//初始化函数,初始化指令
    srand(time(NULL));
    int ok=1,j=0;
    for(int i=0;i<32;){
        if(j==10){
            i++; j=0;
            if(i>=32) break;
        }
        if(ok==1){
            r=random(320);
            page[i][j++]=r;
            page[i][j++]=r+1;
            ok=2;//标记进入第二个随机数
            continue;
        }
        if(ok==2){
            int k=(random(r+1));//1-m+1随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=3;//标记下次进入第二个随机数
            continue;
        }
        if(ok==3){
            int k=(r+2)+(random(320-r-2));//在m+2和320之间随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=1;//下次进入标记进入第一个随机数
            continue;
        }
    }
}
void Init_Page(){//初始化页面
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            page[i][j]=page[i][j]/10;
        }
    }
}
void Oper_LRU(int n){//操作函数,先进先出
    int s=0;//内存的首指
    memset(hashmap,0,sizeof(hashmap));//用于记录当前页面是否在内存中,0:不在,1-4:在某个内存
    memset(q,0,sizeof(q));
    for(int i=0;i<32;i++){//下面是有320条指令的作业的运行情况
        for(int j=0;j<10;j++){
            if(hashmap[page[i][j]]>=1){//页面在内存中
                //printf("当前访问页面在内存中,占用内存的地址为:%d,当前页面的地址为%d\n",hashmap[page[i][j]].id+1,Address(i,j));
                hashmap[page[i][j]]=clock();//记录最近一次访问时间

                sort(q,q+s,cmp);//每次更改重新排序1~4
            }
            else{//当前页面不在内存中,增加缺页次数,并调入内存
                qk++;//增加缺页次数
                node temp,temp1;
                temp.i=i;
                temp.j=j;
                temp.p=page[i][j];
                if(s<n){//内存使用小于4,直接调入
                    //printf("页面不存在,有空的内存空间,直接调入。\n");
                    temp.k=s+1;
                    hashmap[page[i][j]]=clock();//记录进入时间
                    q[s++]=temp;
                    //记录此页已在内存中
                }
                else if(s>=n){//内存已占用4,按先进先出移除一个页面
                    temp1=q[0];//取出队首元素
                    //printf("页面不存在,内存空间已满,按算法移除页面为:%d,其地址为:%d,它占用的内存块为:%d\n",temp1.p,Address(temp1.i,temp1.j),temp1.k);
                    temp.k=temp1.k;
                    hashmap[page[temp1.i][temp1.j]]=0;//变为未访问
                    q[0]=temp;
                    hashmap[page[i][j]]=clock();//记录进入时间
                }
                sort(q,q+s,cmp);//每次更改重新排序1~4
            }
            for(int k=0;k<n;k++){
                printf("%02d ",q[k].p);
            }
            printf("\n");
        }
    }
}

void Show(){
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            printf("%d ",page[i][j]);
        }
        printf("\n");
    }
}

void Print(){
    printf("缺页次数为:%d\n",qk);
    printf("命中率为:%.3lf%%\n",1.0*(320-qk)/320*100);
}

int cmp(node a,node b){//实现比较函数
    return hashmap[a.p]<hashmap[b.p];//最近最少使用的页面小的排在最前面
}
  • 最佳置换(OPT)算法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<ctime>
#include<cstring>
#include<cstdlib>
using namespace std;
struct node{
    int i,j;//进入内存的页面数和页内地址
    int p;//页面值
    int k;//记录页面在内存中中的位置1~4
};
struct NN{
    int flag;//表示是否存在在内存中
    int id;//在内存中的位置1~4
};

int page[33][11];//保存页面和指令
int qk=0;//用于记录缺页的次数
node q[136];//定义内存块的个数
int hashmap[330];//一共用320条指令
queue<int> qp[325];//保存每一个页面在未来的位置到队列中

double random();//生成[0,1]之间的均匀数字
int random(int m);//生成[0,m-1]之间的均匀随机数
void Init(int r);//定义初始化函数,初始值为r
void Init_Page();//定义page初始化函数
void Show();//显示页面信息
int Address(int i,int j);//计算每个页面对应的地址
void Oper_OPT(int n);//LRU操作算法
void Print();
int cmp(node a,node b);//定义比较函数

int main()
{
    /**
    freopen("input.txt","r",stdin);
    freopen("OPT.txt","w",stdout);
    **/
    Init(56);
    Init_Page();
    printf("调入页面:\n");
    Show();
    Oper_OPT(4);//此处传入的参数不同,可用内存不同
    Print();
	return 0;
}
double random(){//生成[0,1]之间的均匀数字
    return (double) rand() / RAND_MAX;
}

int random(int m){//生成[0,m-1]之间的均匀随机数
    return (int) (random()*(m-1)+0.5);
}
int Address(int i,int j){//计算每个页面对应的地址
    return i*10+j;
}

void Init(int r){//初始化函数,初始化指令
    srand(time(NULL));
    int ok=1,j=0;
    for(int i=0;i<32;){
        if(j==10){
            i++; j=0;
            if(i>=32) break;
        }
        if(ok==1){
            r=random(320);
            page[i][j++]=r;
            page[i][j++]=r+1;
            ok=2;//标记进入第二个随机数
            continue;
        }
        if(ok==2){
            int k=(random(r+1));//1-m+1随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=3;//标记下次进入第二个随机数
            continue;
        }
        if(ok==3){
            int k=(r+2)+(random(320-r-2));//在m+2和320之间随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=1;//下次进入标记进入第一个随机数
            continue;
        }
    }
}
void Init_Page(){//初始化页面
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            page[i][j]=page[i][j]/10;
            qp[page[i][j]].push(i*10+j);//保存每个页面出现的位置在队列中
        }
    }
    for(int i=0;i<=320;i++){//将不足的页面赋值为321;标记此页面在以后不会出现,一定会在最前面被替换
        while(qp[i].size()<=320){
            qp[i].push(322);
        }
    }
}
void Oper_OPT(int n){//操作函数,先进先出
    int s=0;//内存的首指
    memset(hashmap,0,sizeof(hashmap));//用于记录当前页面是否在内存中,0:不在,1-4:在某个内存
    memset(q,0,sizeof(q));
    for(int i=0;i<32;i++){//下面是有320条指令的作业的运行情况
        for(int j=0;j<10;j++){
            if(hashmap[page[i][j]]==1){//页面在内存中
                //printf("当前访问页面在内存中,占用内存的地址为:%d,当前页面的地址为%d\n",hashmap[page[i][j]].id+1,Address(i,j));
                qp[page[i][j]].pop();//从队列中移除当前页面的当前位置
                sort(q,q+s,cmp);//每次更改重新排序1~4
            }
            else{//当前页面不在内存中,增加缺页次数,并调入内存
                qk++;//增加缺页次数
                node temp,temp1;
                temp.i=i;
                temp.j=j;
                temp.p=page[i][j];
                qp[page[i][j]].pop();//从队列中移除当前页面的当前位置
                if(s<n){//内存使用小于4,直接调入
                    //printf("页面不存在,有空的内存空间,直接调入。\n");
                    temp.k=s+1;
                    hashmap[page[i][j]]=1;//记录已在内存
                    q[s++]=temp;
                    //记录此页已在内存中
                }
                else if(s>=n){//内存已占用4,按先进先出移除一个页面
                    temp1=q[0];//取出队首元素
                    //printf("页面不存在,内存空间已满,按算法移除页面为:%d,其地址为:%d,它占用的内存块为:%d\n",temp1.p,Address(temp1.i,temp1.j),temp1.k);
                    temp.k=temp1.k;
                    hashmap[page[temp1.i][temp1.j]]=0;//变为未访问
                    q[0]=temp;
                    hashmap[page[i][j]]=1;//记录进入内存
                }
                sort(q,q+s,cmp);//每次更改重新排序1~4
            }
            for(int k=0;k<n;k++){
                printf("%02d ",q[k].p);
            }
            printf("\n");
        }
    }
}

void Show(){
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            printf("%d ",page[i][j]);
        }
        printf("\n");
    }
}

void Print(){
    printf("缺页次数为:%d\n",qk);
    printf("命中率为:%.3lf%%\n",1.0*(320-qk)/320*100);
}

int cmp(node a,node b){//实现比较函数
    return qp[a.p].front()>qp[b.p].front();//未来一段时间出现的晚的在前面
}
  • 最少访问(LFU)算法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<ctime>
#include<cstring>
#include<cstdlib>
using namespace std;
struct node{
    int i,j;//进入内存的页面数和页内地址
    int p;//页面值
    int k;//记录页面在内存中中的位置1~4
};
struct NN{
    int flag;//表示是否存在在内存中
    int id;//在内存中的位置1~4
};

int page[33][11];//保存页面和指令
int qk=0;//用于记录缺页的次数
node q[136];//定义内存块的个数
int hashmap[330];//一共用320条指令

double random();//生成[0,1]之间的均匀数字
int random(int m);//生成[0,m-1]之间的均匀随机数
void Init(int r);//定义初始化函数,初始值为r
void Init_Page();//定义page初始化函数
void Show();//显示页面信息
int Address(int i,int j);//计算每个页面对应的地址
void Oper_LFU(int n);//FIFO操作算法
void Print();
int cmp(node a,node b);//定义比较函数

int main()
{
    freopen("input.txt","r",stdin);
    freopen("output16.txt","w",stdout);
    Init(56);
    Init_Page();
    printf("调入页面:\n");
    Show();
    Oper_LFU(4);
    Print();
	return 0;
}
double random(){//生成[0,1]之间的均匀数字
    return (double) rand() / RAND_MAX;
}

int random(int m){//生成[0,m-1]之间的均匀随机数
    return (int) (random()*(m-1)+0.5);
}
int Address(int i,int j){//计算每个页面对应的地址
    return i*10+j;
}

void Init(int r){//初始化函数,初始化指令
    srand(time(NULL));
    int ok=1,j=0;
    for(int i=0;i<32;){
        if(j==10){
            i++; j=0;
            if(i>=32) break;
        }
        if(ok==1){
            r=random(320);
            page[i][j++]=r;
            page[i][j++]=r+1;
            ok=2;//标记进入第二个随机数
            continue;
        }
        if(ok==2){
            int k=(random(r+1));//1-m+1随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=3;//标记下次进入第二个随机数
            continue;
        }
        if(ok==3){
            int k=(r+2)+(random(320-r-2));//在m+2和320之间随机取一个数
            page[i][j++]=k;
            page[i][j++]=k+1;
            ok=1;//下次进入标记进入第一个随机数
            continue;
        }
    }
}
void Init_Page(){//初始化页面
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            page[i][j]=page[i][j]/10;
        }
    }
}
void Oper_LFU(int n){//操作函数,先进先出
    int s=0;//内存的首指
    memset(hashmap,0,sizeof(hashmap));//用于记录当前页面是否在内存中,0:不在,1-4:在某个内存
    memset(q,0,sizeof(q));
    for(int i=0;i<32;i++){//下面是有320条指令的作业的运行情况
        for(int j=0;j<10;j++){
            if(hashmap[page[i][j]]>=1){//页面在内存中
                //printf("当前访问页面在内存中,占用内存的地址为:%d,当前页面的地址为%d\n",hashmap[page[i][j]].id+1,Address(i,j));
                hashmap[page[i][j]]++;//增加访问次数

                sort(q,q+s,cmp);//每次更改重新排序1~4
            }
            else{//当前页面不在内存中,增加缺页次数,并调入内存
                qk++;//增加缺页次数
                node temp,temp1;
                temp.i=i;
                temp.j=j;
                temp.p=page[i][j];
                if(s<n){//内存使用小于4,直接调入
                    //printf("页面不存在,有空的内存空间,直接调入。\n");
                    temp.k=s+1;
                    hashmap[page[i][j]]=1;
                    q[s++]=temp;
                    //记录此页已在内存中
                }
                else if(s>=n){//内存已占用4,按先进先出移除一个页面
                    temp1=q[0];//取出队首元素
                    //printf("页面不存在,内存空间已满,按算法移除页面为:%d,其地址为:%d,它占用的内存块为:%d\n",temp1.p,Address(temp1.i,temp1.j),temp1.k);
                    temp.k=temp1.k;
                    hashmap[page[temp1.i][temp1.j]]=0;//变为未访问
                    q[0]=temp;
                    hashmap[page[i][j]]=1;
                }
                sort(q,q+s,cmp);//每次更改重新排序1~4
            }
            for(int k=0;k<n;k++){
                printf("%02d ",q[k].p);
            }
            printf("\n");
        }
    }
}

void Show(){
    for(int i=0;i<32;i++){
        for(int j=0;j<10;j++){
            printf("%d ",page[i][j]);
        }
        printf("\n");
    }
}

void Print(){
    printf("缺页次数为:%d\n",qk);
    printf("命中率为:%.3lf%%\n",1.0*(320-qk)/320*100);
}

int cmp(node a,node b){//实现比较函数
    return hashmap[a.p]<hashmap[b.p];//访问次数小的排在最前面
}
   
Brain Storming

1.如果增加分配给作业的内存块数,将会对作业运行过程中的缺页率产生什么影响?

        一般情况下,分配作业的内存块数越多,也就说明该作业在内存中的指令就越多,权限是所有指令都在内存块中,极限命中率是1。对LRU算法来讲,缺页率会降低;OPT算法缺页率会降低。FIFO算法的缺页率会提高。

2.为什么一般情况下,LRU具有FIFO更好的性能?

        因为FIFO置换算法设计相对简单,容易理解,它的效率并不总是能达到令人满意的效果。这个算法只有在顺序访问地址空间是才能达到理想效果,但根据程序的局部性原理,那些经常别访问的页面往往要在主存中停留的最久,FIFO算法却将会将其换出页面,留下的只是一些新调入的指令,这将导致内存频繁换页。LRU则将选择在最近一段时间里最近没有使用过的页面予以置换,是与每个页面最后使用的时间有关的。当必须置换一个页面的时候,LRU选择过去一段时间里最久未被使用的页面。这种算法以最近的过去作为最近的将来的近似,较好地利用了程序的局部性原理。故一般情况下,能取得较好的效果,是经常采用的页面置换算法。

LRU具有FIFO更好的性能

原文链接:http://blog.csdn.net/fool_ran/article/details/42617481





展开阅读全文

没有更多推荐了,返回首页