实验八 页面置换模拟程序设计

本实验通过软件模拟请求页式存储管理中的页面置换过程,重点研究了OPT、FIFO和LRU三种页面置换算法,并对比分析了它们的优缺点。实验采用C语言编程环境,详细介绍了数据结构设计、主程序流程、指令流生成等关键环节。

一、实验目的

1、通过软件模拟页面置换过程,加深对请求页式存储管理实现原理的理解

2、理解和掌握OPT、FIFO和LRU三种页面置换算法,深入分析三者之间的优缺点。

二、实验环境

硬件环境:计算机一台,局域网环境;

软件环境: Windows或Linux操作系统, C语言编程环境。

三、实验内容和步骤

参考设计思路

(1)重要数据结构

① 页表数据结构

typedef struct

{

 int vmn;

 int pmn;

 int exist;

 int time;

 }vpage_item;

 vpage_item page_table[VM_PAGE];

页表是虚地址向物理地址转换的依据,包含虚页号所对应的实页号,是否在物理内存中。

页表中增加了一个time项,用于替换算法选择淘汰页面,在不同的替换算法中,time含义不一样。

在LRU算法中,time为最近访问的时间。该虚页每访问一次,time置为当前访问时刻,淘汰页面时,淘汰time值最小的,即最久没有被使用的。

在FIFO算法中,time为该虚页进入内存的时间。只有当该虚页从外存进入内存时,才置该标志。淘汰页面时,淘汰time值最小的,即最早进入内存的虚页。

在OPT算法中,time没有任何意义。

② 物理页位图数据结构

vpage_item * ppage_bitmap[PM_PAGE];

物理页位图是用于记录物理页是否被使用,用于物理页内存的分配。正常情况下是一个数组,元素值为0时,代表相应物理页没有装入任何虚页,值为1时,代表该物理页装入虚页。但为方便替换算法检索要替换出去的虚页,数组的每个元素值为当前放在该物理页的页表项的指针。若值为NULL,则表示该物理页没有被占用,当值不为NULL时,表示正在占用该物理页的虚页。

③指令相关数据结构

//每条指令信息

typedef struct{

int  num;

int  vpage;

int  offset;

int  inflow;

}instr_item;

//指令数组

instr_item instr_array[TOTAL_INSTR];

//指令流数据结构

struct instr_flow{

instr_item *instr;

struct instr_flow *next;

};

//指令流头数据结构

struct instr_flow_head{

int num;

struct instr_flow *next;

};

struct instr_flow_head iflow_head;

每条指令包括指令号、该指令所属虚页及页内偏移(这两项可以根据指令号计算出来,增加这两项是为了方便编程)。inflow是一个辅助项,用于构建指令流。

本题要求,按照规则生成的指令流中,应包含所有的共320条指令。但每次随机生成的指令号,可能已在指令流中,因此最终指令流中的指令数可能远远超过320条指令。

设置inflow的目的是为了便于统计是否320条指令均已加入到指令流中。在该条指令加入到指令流中时,如果inflow为0,表示该指令尚未在指令流中,则统计数加1;如果inflow为1,表示该指令已经加入过指令流,该指令虽然再次加入指令流,但统计数不增加。这样,当统计计数为320时,表示所有的指令均已加入到指令流中。

struct instr_flow为指令流数据结构,struct instr_flow_head始终指向指令流的头,其中num用于指令流中指令数量计数,用于计算缺页率。

(2)主程序,如下图所示。

(3)指令流生成流程

指令流的生成按照实验要求生成,其算法流程如下图所示。


(4)物理内存分配流程

物理内存分配时,需要根据当前置换算法选择淘汰页面。其算法流程下图所示。

(5)运行流程图,如下图所示。

 

(6)三种置换算法

①OPT算法:在当前指令的后续指令流中,寻找已在内存中的虚页,哪个最远才被使用,反过来,如果先找到最近三个(物理页面总数为4)也在内存中的虚页,则剩下的那个虚页肯定就是最远才被使用的虚页,该虚页被淘汰,其物理内存分配给当前指令所在的虚页。

②FIFO算法:在已在物理内存中的虚页中,寻找time最小的虚页(最早进入物理内存的虚页),该虚页即是被淘汰的虚页。

③LRU算法:思想同FIFO算法,但time最小的虚页含义是最久没有被使用的虚页。

在这三种置换算法中,OPT的算法稍微复杂一些,下图给了该算法的程序流程图。

程序代码

#include <iostream>
#define VM_PAGE 32      /*假设每个页面可以存放10条指令,则共有32个虚页*/
#define PM_PAGE 4       /*分配给作业的内存块数为4*/
#define TOTAL_INSTR 320 /*320条指令*/
using namespace std;
int instr_count = 0;
typedef struct
{
    int vmn; //虚页号
    int pmn;//实页号
    int exist;//是否存在内存
    int time;//时间,作为置换依据
}vpage_item;
vpage_item page_table[VM_PAGE];//虚页表
vpage_item* ppage_bitmap[PM_PAGE]; //实页表

//每条指令信息
typedef struct {
    int  num;//指令号
    int  vpage;//虚页号
    int  offset;//页内偏移
    int  inflow;//是否在指令流中
}instr_item;

//指令数组
instr_item instr_array[TOTAL_INSTR];

//指令流数据结构
struct instr_flow {
    instr_item* instr;
    struct instr_flow* next;
};
//指令流头数据结构
struct instr_flow_head {
    int num = 0;//用于指令流中指令数量计数
    struct instr_flow* next;
};
struct instr_flow_head iflow_head;

void Init_PTable() //页表初始化
{
    for (int i = 0; i < VM_PAGE; i++)
    {
        page_table[i].vmn = i + 1;  //虚页号
        page_table[i].pmn = -1;    //实页号
        page_table[i].exist = 0;
        page_table[i].time = -1;
    }
    for (int i = 0; i < PM_PAGE; i++)
    {
        ppage_bitmap[i] = NULL;
    }
}

void Init_Instr()
{
    int n, count = 1, i = 0,m;
    for (i = 0; i < TOTAL_INSTR; i++)
    {
        instr_array[i].num = i;
        if (count % 10 != 0)
            m = count / 10 + 1;
        else
            m = count / 10;
        instr_array[i].vpage = m;
        instr_array[i].offset = count - (m - 1) * 10 - 1;
        instr_array[i].inflow = 0;
        count++;
    }

    srand((unsigned)time(NULL));
    instr_flow* p_instr_flow = new instr_flow;
    
    iflow_head.next = p_instr_flow;
    while(true){
        n = rand() % TOTAL_INSTR;
        if (instr_array[n].inflow == 0) {
            instr_array[n].inflow = 1;
            iflow_head.num++;
            
        }
        instr_count++;
            p_instr_flow->instr = new instr_item;
            p_instr_flow->instr = instr_array + n;
            
            p_instr_flow->next = new instr_flow;
            printf("%d\t%d\t%d\n", p_instr_flow->instr->num, p_instr_flow->instr->vpage, p_instr_flow->instr->offset);
            
            if (iflow_head.num == TOTAL_INSTR) {//所有指令均位于指令流中
                p_instr_flow->next = NULL;
                break;             
            }
            p_instr_flow = p_instr_flow->next;
    }
}
void FIFO()/*FIFO页面置换算法*/
{
    int k = 0;
    int i;
    int missing_page_count = 0;
    int current_time = 0;
    instr_flow* p_instr_flow = new instr_flow;
    p_instr_flow = iflow_head.next;
    while (p_instr_flow!=NULL)
    {
        if (page_table[p_instr_flow->instr->vpage - 1].exist == 0)
        {
            missing_page_count++;
            if (k < PM_PAGE)
            {
                if (ppage_bitmap[k] == NULL) /*找到一个空闲物理块*/
                {
                    ppage_bitmap[k] = &page_table[p_instr_flow->instr->vpage - 1];
                    ppage_bitmap[k]->exist = 1;
                    ppage_bitmap[k]->pmn = k;
                    ppage_bitmap[k]->time = current_time;
                    k++;
                }
            }
            else
            {
                int temp = ppage_bitmap[0]->time;	/*记录物理块中作业最早到达时间*/
                int j = 0;                    /*记录应当被替换的物理块号*/
                for (i = 0; i < PM_PAGE; i++)   /*寻找最早到达的作业*/
                {
                    if (ppage_bitmap[i]->time < temp)
                    {
                        temp = ppage_bitmap[i]->time;
                        j = i;
                    }
                }
                ppage_bitmap[j]->exist = 0;
                ppage_bitmap[j] = &page_table[p_instr_flow->instr->vpage - 1];      /*更新页表项*/
                ppage_bitmap[j]->exist = 1;
                ppage_bitmap[j]->pmn = j;
                ppage_bitmap[j]->time = current_time;
            }
           

        }
        current_time++;
        p_instr_flow = p_instr_flow->next;
    }
    printf("FIFO算法缺页次数为:%d\t缺页率为:%f\t置换次数为:%d\t置换率为:%f\n", missing_page_count, missing_page_count / (float)instr_count, missing_page_count - 4, (missing_page_count - 4) / (float)instr_count);
}
void LRU()
{
    int k = 0;
    int i;
    int missing_page_count = 0;
    int current_time = 0;
    instr_flow* p_instr_flow = new instr_flow;
    //bool isleft = true;   /*当前物理块中是否有剩余*/
    p_instr_flow = iflow_head.next;
    while (p_instr_flow != NULL)
    {
        if (page_table[p_instr_flow->instr->vpage - 1].exist == 0)/*当前指令不存在物理块中*/
        {
            missing_page_count++;
            if (k < PM_PAGE)
            {
                if (ppage_bitmap[k] == NULL) /*找到一个空闲物理块*/
                {
                    ppage_bitmap[k] = &page_table[p_instr_flow->instr->vpage - 1];
                    ppage_bitmap[k]->exist = 1;
                    ppage_bitmap[k]->pmn = k;
                    ppage_bitmap[k]->time = current_time;
                    k++;
                }
            }
            else
            {
                int temp = ppage_bitmap[0]->time;	/*记录物理块中作业最早到达时间*/
                int j = 0;                    /*记录应当被替换的物理块号*/
                for (i = 0; i < PM_PAGE; i++)/*找到时间最小的物理块,也就是最久未使用的*/
                {
                    if (ppage_bitmap[i]->time < temp)
                    {
                        temp = ppage_bitmap[i]->time;
                        j = i;
                    }
                }
                ppage_bitmap[j]->exist = 0;
                ppage_bitmap[j] = &page_table[p_instr_flow->instr->vpage - 1];      /*更新页表项*/
                ppage_bitmap[j]->exist = 1;
                ppage_bitmap[j]->pmn = j;
                ppage_bitmap[j]->time = current_time;
            }
        }
        else/*当前指令在物理块中,时间更新*/
        {
            page_table[p_instr_flow->instr->vpage - 1].time = current_time;
        }
        current_time++;
        p_instr_flow = p_instr_flow->next;
    }
    printf("LRU算法缺页次数为:%d\t缺页率为:%f\t置换次数为:%d\t置换率为:%f\n", missing_page_count, missing_page_count / (float)instr_count, missing_page_count - 4, (missing_page_count - 4) / (float)instr_count);
}

void OPT()
{
    int k = 0;
    int missing_page_count = 0;
    int current_time = 0;
    instr_flow* p_instr_flow = new instr_flow;
    p_instr_flow = iflow_head.next;
    while (p_instr_flow != NULL) {
        if (page_table[p_instr_flow->instr->vpage - 1].exist == 0) {
            missing_page_count++;
            if (k < PM_PAGE)
            {
                if (ppage_bitmap[k] == NULL) /*找到一个空闲物理块*/
                {
                    ppage_bitmap[k] = &page_table[p_instr_flow->instr->vpage - 1];
                    ppage_bitmap[k]->exist = 1;
                    ppage_bitmap[k]->pmn = k;
                    ppage_bitmap[k]->time = current_time;
                    k++;
                }
            }
            else {
                int used[VM_PAGE] = { 0 };/*记录哪些虚页已经使用*/
                int i;
                instr_flow* pp_instr_flow = p_instr_flow->next;
                int count = 0;
                /*便利剩余指令*/
                for (pp_instr_flow; pp_instr_flow != NULL; pp_instr_flow = pp_instr_flow->next) 
                {
                    if (page_table[pp_instr_flow->instr->vpage - 1].exist == 1) 
                    {
                        used[page_table[pp_instr_flow->instr->vpage  - 1].vmn - 1] = 1;
                    }
                    for (i = 0; i < VM_PAGE; i++) {
                        if (used[i] == 1) {
                            count++;
                        }
                    }
                    if (count == 3) {
                        break;
                    }
                }
                for (i = 0; i < PM_PAGE; i++) {
                    if (used[ppage_bitmap[i]->vmn - 1] == 0) {
                        ppage_bitmap[i]->exist = 0;
                        ppage_bitmap[i] = &page_table[p_instr_flow->instr->vpage - 1];
                        ppage_bitmap[i]->exist = 1;
                        ppage_bitmap[i]->pmn = i;
                        ppage_bitmap[i]->time = current_time;
                    }
                }
            }
        }
        current_time++;
        p_instr_flow = p_instr_flow->next;
    }
    printf("OPT算法缺页次数为:%d\t缺页率为:%f\t置换次数为:%d\t置换率为:%f", missing_page_count, missing_page_count / (float)instr_count, missing_page_count - 4, (missing_page_count - 4) / (float)instr_count);
}
int main()
{
    Init_PTable();
    cout << "指令流如下:" << endl;
    printf("-----------------------------------------------\n");
    printf("指令号\t所在页\t页内位移\n");
    printf("-----------------------------------------------\n");
    Init_Instr();
    printf("-----------------------------------------------\n");
    cout << "共计" << instr_count << "条指令" << endl;
    cout << endl << endl;
    FIFO();
    Init_PTable();
    LRU();
    Init_PTable();
    OPT();
    return 0;
    
}

实验结果

 实验分析

①分析实验结果产生的原因,总结从实验观察到的结果,分析三种置换算法的缺页率的差异。

FIFO算法每次先替换最先进入的页面,LRU算法每次先替换最近最久未使用的页面,OPT算法每次先替换将来最长时间内不再被访问的页面。所以FIFO算法的置换率相对较大,而LRU算法考虑到了程序的局部性原理,相对较小,OPT算法也相对较小。

②结合操作系统课程中讲授的原理,写出本次实验的心得体会。

FIFO算法置换最先调入内存的页面,即置换在内存中驻留时间最久的页面。按照进入内存的先后次序排列成队列,从队尾进入,从队首删除。但是该算法会淘汰经常访问的页面,不适应进程实际运行的规律。

LRU算法置换最近一段时间以来最长时间未访问过的页面。根据程序局部性原理,刚被访问的页面,可能马上又要被访问;而较长时间内没有被访问的页面,可能最近不会被访问。普偏地适用于各种类型的程序,但是系统要时时刻刻对各页的访问历史情况加以记录和更新,开销太大,因此LRU算法必须要有硬件的支持。

OPT算法置换以后不再被访问,或者在将来最迟才回被访问的页面,缺页中断率最低。但是该算法需要依据以后各业的使用情况。所以OPT算法不可能实现。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ace2NoU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值