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

前言

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

using 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;
}
  • 18
    点赞
  • 131
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一、课程设计目的 通过请求页式管理方式中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请 求页式存储管理中的页面置换算法。 容 二、课程设计内容 模拟实现 OPT(最佳置换)、FIFO 和 LRU 算法,并计算缺页率。 示 三、要求及提示 本题目必须单人完成。 1、首先用随机数生成函数产生一个“指令将要访问的地址序列”,然后将地址序列变换 成相应的页地址流(即页访问序列),再计算不同算法下的命中率。 2、通过随机数产生一个地址序列,共产生 400 条。其中 50%的地址访问是顺序执行的, 另外 50%就是非顺序执行。且地址在前半部地址空间和后半部地址空间均匀分布。具体产 生方法如下: 1) 在前半部地址空间,即[0,199]中随机选一数 m,记录到地址流数组中(这是 非顺序执行); 2) 接着“顺序执行一条指令”,即执行地址为 m+1 的指令,把 m+1 记录下来; 3) 在后半部地址空间,[200,399]中随机选一数 m’,作为新指令地址; 4) 顺序执行一条指令,其地址为 m’+1; 5) 重复步骤 1~4,直到产生 400 个指令地址。 3、将指令地址流变换成页地址(页号)流,简化假设为: 1) 页面大小为 1K(这里 K 只是表示一个单位,不必是 1024B); 2) 用户虚存容量为 40K; 3) 用户内存容量为 4 个页框到 40 个页框; 6 4) 用户虚存中,每 K 存放 10 条指令,所以那 400 条指令访问地址所对应的页地 址(页号)流为:指令访问地址为[0,9]的地址为第 0 页;指令访问地址为[10, 19]的地址为第 1 页;……。按这种方式,把 400 条指令组织进“40 页”,并 将“要访问的页号序列”记录到页地址流数组中。 4、循环运行,使用户内存容量从 4 页框到 40 页框。计算每个内存容量下不同页面置换 算法的命中率。输出结果可以为: 页框数 OPT 缺页率 FIFO 缺页率 LRU 缺页率 [4] OPT:0.5566 FIFO:0.4455 LRU:0.5500 [5] OPT:0.6644 FIFO:0.5544 LRU:0.5588 …… …… …… …… [39] OPT:0.9000 FIFO:0.9000 LRU:0.9000 [40] OPT:1.0000 FIFO:1.0000 LRU:1.0000 注 1:在某一次实验中,可能 FIFO 比 LRU 性能更好,但足够多次的实验表明 LRU 的平均性能比 FIFO 更好。 注 2:计算缺页率时,以页框填满之前和之后的总缺页次数计算。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值