实验三 存储管理

一、实验目的

存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。本实验的目的是通过请求页式管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。

二、实验内容

1、通过计算不同算法的命中率比较算法的优劣。同时也考虑了用户内存容量对命中率的影响。

2、页面失效次数为每次访问相应指令时,该指令所对应的页不在内存中的次数。

3、在本实验中,假定页面大小为 1k,用户虚存容量为 32k,用户内存容量为 4 页到 32 页。

三、实验要求

1、计算并输出下属算法在不同内存容量下的命中率。

1)先进先出的算法(FIFO);

2)最近最少使用算法(LRU);

2、address通过随机数产生一个指令序列,共320条指令。

指令的地址按下述原则生成:

1)50%的指令是顺序执行的

2)25%的指令是均匀分布在前地址部分

3)25%的指令是均匀分布在后地址部分

四、实验过程

具体的实施方法是:

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

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

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

址为 m1;

4)顺序执行一条指令,地址为m1+1的指令

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

6)重复上述步骤 1)~5),直到执行320次指令

五、实验分析与实现

1、避免伪随机数生成使用c++的time.h的库

#include <time.h>

使用srand((unsigned)time(NULL))及rand()实现

Address::Address()
{
    cout<<"Start memory management."<<'\n';
    cout<<"Producing address flow, wait for while, please."<<'\n';
    int j=0;
    flag=true;
    srand((unsigned)time(NULL));
    
    /* 生成指令序列 */
    while(j<320)
    {
        /* 在[0,319]的指令地址之间随机选取一起点 m; */
        m=rand()%320;
        /* 顺序执行一条指令,即执行地址为 m+1 的指令 */
        order[j]=m+1;
        cout<<order[j++]<<'\t';
        /* 在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为 m1 */
        m1=rand()%(m+2);
        /* 顺序执行一条指令,地址为 m1+1 的指令 */
        order[j]=m1+1;
        cout<<order[j++]<<'\t';
        /* 在后地址[m’+2,319]中随机选取一条指令并执行 */
        order[j]=(m1+2)+(rand()%(320-m1-2));
        cout<<order[j++]<<'\t';
    }
}

2、队列的数据结构的实现,使用模板类实现队列

linkqueue.h文件:

#include <iostream>
using namespace std;

template <class T>
struct Node
{
    T data;
    Node<T> *next;
};

template <class T>
class LinkQueue
{
public:
    LinkQueue(); /* 构造函数,初始化空的链队列 */
    ~LinkQueue(); /* 析构函数,释放链队中各结点的存储空间 */
    void EnQueue(T x); /* 将元素x入队 */
    T DeQueue(); /* 将队头元素出队 */
    void DeQueue(T x); /* 将队头元素出队 */
    void SetNullQueue(); /* 队列清空 */
    bool Empty(); /* 判断队列是否为空 */
    bool Exist(T x); /* 判断队列里是否存在这个页面 */
    int GetLength(); /* 返回队列的长度 */
//    friend void FIFO(); /* 先进先出算法 */
//    friend void LRU(); /* 最近最久未使用算法 */

private:
    Node<T> *front, *rear;
    int length;/* 计算队列长度 */
    int m,m1;/* 起点 m,m1 */
    int S; /* 算法号 */
    bool flag; /* 判断输入的算法号是否符合要求 */
    int Msize=2; /* 用户内存空间 */
};

template <class T>
LinkQueue<T>::LinkQueue()
{
    Node <T> *s;
    s=new Node<T>;
    s->next=NULL;
    front=rear=s;
}

template <class T>
LinkQueue<T>::~LinkQueue()
{
    while(front)
    {
        Node <T> *p;
        p=front->next;
        delete front;
        front=p;
    }
}

/* 入队函数 */
template<class T>
void LinkQueue<T>::EnQueue (T x)
{
    Node<T> *s;
    s=new Node<T> ; /* 生成结点s */
    s->data=x;
    s->next =NULL;
    rear->next=s ; /* 将结点s接队尾 */
    rear=s ; /* 队尾指针指向新队尾结点 */
    length++;
}

template <class T>
T LinkQueue<T>:: DeQueue ()
{
    Node<T>*p;
    T x;
    if(rear==front)
        throw "下溢";
    p=front->next;
    x=p->data; /* 暂存队头元素 */
    front->next=p->next; /* 将队头元素所在结点摘链 */
    if (p->next==NULL)
        rear=front; /* 判断出队前队列长度是否为1 */
    length--;
    delete p;
    return x;
}

template <class T>
void LinkQueue<T>::DeQueue (T x)
{
    Node<T>*p,*s;
    if(rear==front)
        throw "下溢";
    p=front;
    s=front->next;
    while(p!=rear)
    {
        if(s->data==x)
        {
            p->next=s->next; /* 将元素所在结点摘链 */
        }
        s=s->next;
        p=p->next;
    }
    if (p->next==rear)
        rear=front; /* 判断出队前队列长度是否为1 */
    length--;
    delete p,s;
}

/* 判断链队列是否为空函数 */
template <class T>
bool LinkQueue<T>::Empty()
{
    if(front==rear)
        return 1;
    else
        return 0;
}

/* 队列清空函数 */
template <class T>
void LinkQueue<T>::SetNullQueue ()
{
    rear = front;
}

/* 返回队列长度 */
template <class T>
int LinkQueue<T>::GetLength ()
{
    return length;
}

/* 判断队列里是否存在这个页面 */
template <class T>
bool LinkQueue<T>::Exist(T x)
{
    Node<T> *p;
    if(rear==front)
        throw "下溢";
    p=front->next;
    while(p!=rear->next)
    {
        if(p->data==x)
        {
            return 1;
        }
        else
            p=p->next;
    }
    return 0;
}

3、实现最近最久未使用算法

步骤:

判断页面是否在队列物理块里面。若不存在则先判断是否29个物理块全部被占用,若未被全部占用,直接将此页插在队列最后面,若全部被占用,则将先进队列的队头元素出队,再将此页面入队,缺页次数+1;若存在,将此页面先出队,再在最后入队,将最近最久未使用的页面放在队首。

/* 最近最久未使用算法 */
void LRU(int order[],int size)
{
    int number=0; /* 初始化缺页次数 */
    LinkQueue<int> q;

    /* 执行320条指令序列 */
    for(int i=0;i<size;i++)
    {
        /* 如果队列为空,则将此页面放入物理块的队列里 */
        if(q.Empty())
        {
            q.EnQueue(order[i]);
            number++;
        }
        else
        {
            /* 判断页面是否在队列物理块里面
             * 若不存在则先判断是否29个物理块全部被占用,
             * 若未被全部占用,直接将此页插在队列最后面,
             * 若全部被占用,则将先进队列的队头元素出队,再将此页面入队
             * 缺页次数+1;
             * 若存在,将此页面先出队,再在最后入队,将最近最久未使用的页面放在队首*/
            if(!q.Exist(order[i]))
            {
                if(q.GetLength()<=29)
                    q.EnQueue(order[i]);
                else
                {
                    q.DeQueue();
                    q.EnQueue(order[i]);
                }
                number++;
            }
            else if(q.Exist(order[i]))
            {
                q.DeQueue(order[i]);
                q.EnQueue(order[i]);
            }
        }
    }
    /* 记录命中率 */
    double rate=1-number/320.0;
    cout<<"LRU算法命中率: "<<rate<<'\t';
}

六、实验过程中的问题及对应思考

1.如何实现先进先出算法?

解决:使用数据结构队列

2.模板类实例定义无效

解决:将模板类.cpp文件内容加到.h文件中。

思考:模板类的实现,脱离具体的使用,是无法单独的编译的;把声明和实现分开的做法也是不可取的,必须把实现全部写在头文件里面。或者在类的定义源文件中使用关键字export,然后其他文件使用时只需包含类的定义头文件就可以。

3.如何利用已有的代码(已实现FIFC算法)实现LRU算法

解决:将最近使用的页面出队,插入到队列最后面,最近未使用的页面排在队列的最前面

七、附录

address.h文件内容:
/* c++头文件 */
#include <iostream>
#include <time.h>

using namespace std;

/* 指令类,生成指令序列 */
class Address
{
public:
    Address();/* 生成指令序列 */
    int Judge(int m);/* 判断输入的算法号是否在[1,4] */
    void GetOrder(int a[]);
private:
    int m,m1;/* 起点 m,m1 */
    int order[320];/* 指令序列 */
    int S; /* 算法号 */
    bool flag; /* 判断输入的算法号是否符合要求 */
};

algorithm.h文件
/* 先进先出算法 */
void FIFO(int order[],int size);
/* 最近最久未使用算法 */
void LRU(int order[],int size);
linkqueue.h文件:
#include <iostream>
using namespace std;

template <class T>
struct Node
{
    T data;
    Node<T> *next;
};

template <class T>
class LinkQueue
{
public:
    LinkQueue(); /* 构造函数,初始化空的链队列 */
    ~LinkQueue(); /* 析构函数,释放链队中各结点的存储空间 */
    void EnQueue(T x); /* 将元素x入队 */
    T DeQueue(); /* 将队头元素出队 */
    void DeQueue(T x); /* 将队头元素出队 */
    void SetNullQueue(); /* 队列清空 */
    bool Empty(); /* 判断队列是否为空 */
    bool Exist(T x); /* 判断队列里是否存在这个页面 */
    int GetLength(); /* 返回队列的长度 */
//    friend void FIFO(); /* 先进先出算法 */
//    friend void LRU(); /* 最近最久未使用算法 */

private:
    Node<T> *front, *rear;
    int length;/* 计算队列长度 */
    int m,m1;/* 起点 m,m1 */
    int S; /* 算法号 */
    bool flag; /* 判断输入的算法号是否符合要求 */
    int Msize=2; /* 用户内存空间 */
};

template <class T>
LinkQueue<T>::LinkQueue()
{
    Node <T> *s;
    s=new Node<T>;
    s->next=NULL;
    front=rear=s;
}

template <class T>
LinkQueue<T>::~LinkQueue()
{
    while(front)
    {
        Node <T> *p;
        p=front->next;
        delete front;
        front=p;
    }
}

/* 入队函数 */
template<class T>
void LinkQueue<T>::EnQueue (T x)
{
    Node<T> *s;
    s=new Node<T> ; /* 生成结点s */
    s->data=x;
    s->next =NULL;
    rear->next=s ; /* 将结点s接队尾 */
    rear=s ; /* 队尾指针指向新队尾结点 */
    length++;
}

template <class T>
T LinkQueue<T>:: DeQueue ()
{
    Node<T>*p;
    T x;
    if(rear==front)
        throw "下溢";
    p=front->next;
    x=p->data; /* 暂存队头元素 */
    front->next=p->next; /* 将队头元素所在结点摘链 */
    if (p->next==NULL)
        rear=front; /* 判断出队前队列长度是否为1 */
    length--;
    delete p;
    return x;
}

template <class T>
void LinkQueue<T>::DeQueue (T x)
{
    Node<T>*p,*s;
    if(rear==front)
        throw "下溢";
    p=front;
    s=front->next;
    while(p!=rear)
    {
        if(s->data==x)
        {
            p->next=s->next; /* 将元素所在结点摘链 */
        }
        s=s->next;
        p=p->next;
    }
    if (p->next==rear)
        rear=front; /* 判断出队前队列长度是否为1 */
    length--;
    delete p,s;
}

/* 判断链队列是否为空函数 */
template <class T>
bool LinkQueue<T>::Empty()
{
    if(front==rear)
        return 1;
    else
        return 0;
}

/* 队列清空函数 */
template <class T>
void LinkQueue<T>::SetNullQueue ()
{
    rear = front;
}

/* 返回队列长度 */
template <class T>
int LinkQueue<T>::GetLength ()
{
    return length;
}

/* 判断队列里是否存在这个页面 */
template <class T>
bool LinkQueue<T>::Exist(T x)
{
    Node<T> *p;
    if(rear==front)
        throw "下溢";
    p=front->next;
    while(p!=rear->next)
    {
        if(p->data==x)
        {
            return 1;
        }
        else
            p=p->next;
    }
    return 0;
}

address.cpp内容
#include "address.h"

Address::Address()
{
    cout<<"Start memory management."<<'\n';
    cout<<"Producing address flow, wait for while, please."<<'\n';
    int j=0;
    flag=true;
    srand((unsigned)time(NULL));
    
    /* 生成指令序列 */
    while(j<320)
    {
        /* 在[0,319]的指令地址之间随机选取一起点 m; */
        m=rand()%320;
        /* 顺序执行一条指令,即执行地址为 m+1 的指令 */
        order[j]=m+1;
        cout<<order[j++]<<'\t';
        /* 在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为 m1 */
        m1=rand()%(m+2);
        /* 顺序执行一条指令,地址为 m1+1 的指令 */
        order[j]=m1+1;
        cout<<order[j++]<<'\t';
        /* 在后地址[m’+2,319]中随机选取一条指令并执行 */
        order[j]=(m1+2)+(rand()%(320-m1-2));
        cout<<order[j++]<<'\t';
    }
}

int Address::Judge(int m)
{
    S=m;
    /* 判断输入的算法号是否在[1,4] */
    switch(S)
    {
    case 1:
        flag=true;
        break;
    case 2:
        flag=true;
        break;
    case 3:
        flag=true;
        cout<<"Wait for this algorithm to be written"<<'\n';
        break;
    case 4:
        flag=true;
        cout<<"Wait for this algorithm to be written"<<'\n';
        break;
    default:
        cout<<"there is not the algorithm in the program"<<'\n';
        flag=false;
    }
    return flag;
}

void Address::GetOrder(int a[])
{
    for(int i=0;i<320;i++)
    {
        a[i]=order[i];
    }
}

algorithm.cpp内容
#include "algorithm.h"
#include "linkqueue.h"

/* 先进先出算法 */
void FIFO(int order[],int size)
{
    int number=0;
    LinkQueue<int> q;
    /* 执行320条指令序列 */
    for(int i=0;i<size;i++)
    {
        /* 如果队列为空,则将此页面放入物理块的队列里 */
        if(q.Empty())
        {
            q.EnQueue(order[i]);
            number++;
        }
        else
        {
            /* 判断页面是否在队列物理块里面
             * 若不存在则先判断是否29个物理块全部被占用,
             * 若未被全部占用,直接将此页插在队列最后面,
             * 若全部被占用,则将先进队列的队头元素出队,再将此页面入队
             * 缺页次数+1;
             * 若存在,则继续进入下一个页面*/
            if(!q.Exist(order[i]))
            {
                if(q.GetLength()<=29)
                    q.EnQueue(order[i]);
                else
                {
                    q.DeQueue();
                    q.EnQueue(order[i]);
                }
                number++;
            }
            else if(q.Exist(order[i]))
                continue;
        }
    }
    double rate=1-number/320.0;
    cout<<"FIFO算法命中率: "<<rate<<'\t';
}

/* 最近最久未使用算法 */
void LRU(int order[],int size)
{
    int number=0; /* 初始化缺页次数 */
    LinkQueue<int> q;

    /* 执行320条指令序列 */
    for(int i=0;i<size;i++)
    {
        /* 如果队列为空,则将此页面放入物理块的队列里 */
        if(q.Empty())
        {
            q.EnQueue(order[i]);
            number++;
        }
        else
        {
            /* 判断页面是否在队列物理块里面
             * 若不存在则先判断是否29个物理块全部被占用,
             * 若未被全部占用,直接将此页插在队列最后面,
             * 若全部被占用,则将先进队列的队头元素出队,再将此页面入队
             * 缺页次数+1;
             * 若存在,将此页面先出队,再在最后入队,将最近最久未使用的页面放在队首*/
            if(!q.Exist(order[i]))
            {
                if(q.GetLength()<=29)
                    q.EnQueue(order[i]);
                else
                {
                    q.DeQueue();
                    q.EnQueue(order[i]);
                }
                number++;
            }
            else if(q.Exist(order[i]))
            {
                q.DeQueue(order[i]);
                q.EnQueue(order[i]);
            }
        }
    }
    /* 记录命中率 */
    double rate=1-number/320.0;
    cout<<"LRU算法命中率: "<<rate<<'\t';
}

main.cpp内容
#include "address.h"
#include "algorithm.h"
#include "linkqueue.h"

int main()
{
    int order[320];/* 指令 */
    int S; /* 算法号 */
    Address ad;
    cout<<"There are algorithms in the program"<<'\n';
    cout<<"\t1、 Optimization algorithm"<<'\n';
    cout<<"\t2、 Least recently used algorithm"<<'\n';
    cout<<"\t3、 First in first out algorithm"<<'\n';
    cout<<"\t4、 Least frequently used algorithm"""<<'\n';
    cout<<"     Select an algorithm number, please."<<endl;
    while(true)
    {
        cin>>S;
        if(ad.Judge(S))
        {
            break;
        }
    }
    ad.GetOrder(order);
    /* 判断输入的算法号是否在[1,4] */
    switch(S)
    {
    case 1:
        cout<<"1";
        FIFO(order,320);
        break;
    case 2:
        cout<<"2";
        LRU(order,320);
        break;
    case 3:
        cout<<"3";
        break;
    case 4:
        cout<<"4";
        break;
    default:
        cout<<"there is not the algorithm in the program"<<'\n';
    }
}


完整虚拟存储管理实验报告!一、实验目的请求页式虚存管理是常用的虚拟存储管理方案之一。通过请求页式虚存管理中对页面置换算法的模拟,有助于理解虚拟存储技术的特点,并加深对请求页式虚存管理的页面调度算法的理解。二、实验环境 Turbo C 2.0/3.0或VC++6.0实验内容本实验要求使用C语言编程模拟一个拥有若干个虚页的进程在给定的若干个实页中运行、并在缺页中断发生时分别使用FIFO和LRU算法进行页面置换的情形。其中虚页的个数可以事先给定(例如10个),对这些虚页访问的页地址流(其长度可以事先给定,例如20次虚页访问)可以由程序随机产生,也可以事先保存在文件中。要求程序运行时屏幕能显示出置换过程中的状态信息并输出访问结束时的页面命中率。程序应允许通过为该进程分配不同的实页数,来比较两种置换算法的稳定性。四、实验说明 1.设计中虚页和实页的表示本设计利用C语言的结构体来描述虚页和实页的结构。pnpfntimepnpfnnext 虚页结构 实页结构在虚页结构中,pn代表虚页号,因为共10个虚页,所以pn的取值范围是0—9。pfn代表实页号,当一虚页未装入实页时,此项值为-1;当该虚页已装入某一实页时,此项值为所装入的实页的实页号pfn。time项在FIFO算法中不使用,在LRU中用来存放对该虚页的最近访问时间。在实页结构中,pn代表虚页号,表示pn所代表的虚页目前正放在此实页中。pfn代表实页号,取值范围(0—n-1)由动态指派的实页数n所决定。next是一个指向实页结构体的指针,用于多个实页以链表形式组织起来,关于实页链表的组织详见下面第4点。2.关于缺页次数的统计为计算命中率,需要统计在20次的虚页访问中命中的次数。为此,程序应设置一个计数器count,来统计虚页命中发生的次数。每当所访问的虚页的pfn项值不为-1,表示此虚页已被装入某实页内,此虚页被命中,count加1。最终命中率=count/20*100%。3.LRU算法中“最近最久未用”页面的确定为了能找到“最近最久未用”的虚页面,程序中可引入一个时间计数器countime,每当要访问一个虚页面时,countime的值加1,然后将所要访问的虚页的time项值设置为增值后的当前countime值,表示该虚页的最后一次被访问时间。当LRU算法需要置换时,从所有已分配实页的虚页中找出time值为最小的虚页就是“最近最久未用”的虚页面,应该将它置换出去。4.算法中实页的组织因为能分配的实页数n是在程序运行时由用户动态指派的,所以应使用链表组织动态产生的多个实页。为了调度算法实现的方便,可以考虑引入free和busy两个链表:free链表用于组织未分配出去的实页,首指针为free_head,初始时n个实页都处于free链表中;busy链表用于组织已分配出去的实页,首指针为busy_head,尾指针为busy_tail,初始值都为null。当所要访问的一个虚页不在实页中时,将产生缺页中断。此时若free链表不为空,就取下链表首指针所指的实页,并分配给该虚页。若free链表为空,则说明n个实页已全部分配出去,此时应进行页面置换:对于FIFO算法要将busy_head 所指的实页从busy链表中取下,分配给该虚页,然后再将该实页插入到busy链表尾部;对于LRU算法则要从所有已分配实页的虚页中找出time值为最小的虚页,将该虚页从装载它的那个实页中置换出去,并在该实页中装入当前正要访问的虚页。~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值