实验七 虚拟存储管理实验

本文通过实现和比较请求页式存储管理的三种算法(OPT、FIFO和LRU),深入理解页面淘汰与地址转换,通过编写模拟程序演示了它们的工作原理及性能差异。实验涉及高级语言编程、数据结构和存储管理模型,提供了实际操作示例和缺页中断分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实验目的

  1. 通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解。熟悉虚存管理的各种页面淘汰算法
  2. 通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。

二、实验类型
综合性实验。综合高级语言、数据结构、存储管理模型等多方面的知识
三、实验示例

例题

设计一个请求页式存储管理方案。并编写模拟程序实现之。产生一个需要访问的指令地址流。它是一系列需要访问的指令的地址。为不失一般性,你可以适当地(用人工指定地方法或用随机数产生器)生成这个序列,使得
50%的指令是顺序执行的。25%的指令均匀地散布在前地址部分,25%的地址是均匀地散布在后地址部分 为简单起见。页面淘汰算法采用
FIFO页面淘汰算法,并且在淘汰一页时,只将该页在页表中抹去。而不再判断它是否被改写过,也不将它写回到辅存。

具体的做法可以是:
  产生一个需要访问的指令地址流;
  指令合适的页面尺寸(例如以 1K或2K为1页);
指定内存页表的最大长度,并对页表进行初始化;
每访问一个地址时,首先要计算该地址所在的页的页号,然后查页表,判断该页是否在主存——如果该页已在主存,则打印页表情况;如果该页不在主存且页表未满,则调入一页并打印页表情况;如果该页不足主存且页表已满,则按 FIFO页面淘汰算法淘汰一页后调入所需的页,打印页表情况; 逐个地址访问,直到所有地址访问完毕。

存储管理算法的流程图如下:
在这里插入图片描述
四、实验选题

编写并调试完成请求页式存储管理程序。(参考课本P145-149例子)
页面置换算法:最佳置换算法(OPT)、先进先出算法(FIFO)和最近最少用算法(LRU)。
要求打印每个页面置换算法的页面置换变化示意图、缺页中断次数和缺页中断率,以比较各种算法的优缺点。


具体实现:

  1. 头文件,全局变量等
#include <iostream>
#include<fstream>
#include<vector>
using namespace std;

//【约定】作业名不能为0,可以取1~9。

int read[50];  //存取文件读取的作业
int page_length;   //页内作业数,最大不超过9
double page_fault_interrupt = 0;   //记录缺页中断次数

MyLinkedList *the_page = new MyLinkedList();
int total = read_data(0);
  1. 链表类
//一页,容量为page_content
class MyLinkedList {
public:
    struct LinkedNode {
        int val;
        LinkedNode *next;

        LinkedNode(int val) : val(val), next(nullptr) {}
    };

private:
    LinkedNode *dummy_head;
    int size;

public:
    MyLinkedList() {
        //虚拟头节点
        dummy_head = new LinkedNode(0);
        size = 0;
    }

    int get(int index) {
        if (index > size - 1)
            return -1;

        LinkedNode *tmp = dummy_head;
        for (int i = 0; i <= index; i++) {
            tmp = tmp->next;
        }
        return tmp->val;
    }

    void addAtHead(int val) {
        auto *head = new LinkedNode(val);
        head->next = dummy_head->next;
        dummy_head->next = head;
        size++;
    }

    void addAtTail(int val) {
        LinkedNode *last = dummy_head;
        while (last->next != NULL) {
            last = last->next;
        }
        last->next = new LinkedNode(val);
        size++;
    }

    void addAtIndex(int index, int val) {
        LinkedNode *tmp = dummy_head;
        for (int i = 0; i < index; i++) {
            tmp = tmp->next;
        }
        auto *addedNode = new LinkedNode(val);
        if (tmp != nullptr) {
            addedNode->next = tmp->next;
            tmp->next = addedNode;
            size++;
        }
    }

    void deleteAtIndex(int index) {
        LinkedNode *deletedNode = nullptr;
        LinkedNode *tmp = dummy_head;
        for (int i = 0; i < index; i++) {
            tmp = tmp->next;
        }
        if (tmp != nullptr)
            deletedNode = tmp->next;
        if (tmp != nullptr && tmp->next != nullptr) {
            tmp->next = tmp->next->next;
            delete deletedNode;
            size--;
        }
    }

    int find(int val) {      //找到返回index,没有返回-1
        LinkedNode *tmp = dummy_head->next;
        for (int i = 0; i < size; i++) {
            if (tmp->val == val)
                return i;
            tmp = tmp->next;
        }
        return -1;
    }

    int getSize() const {
        return size;
    }

    void Myprint(int break_or_not, int insert) {
        if(break_or_not)
            page_fault_interrupt++;     //更新缺页中断次数
        cout << insert << " -> ";
        LinkedNode *t = dummy_head;
        int i = page_length + 1;
        while (t->next) {
            t = t->next;
            cout << "|" << t->val;
            i--;
        }
        while (i--) {
            cout << "| ";
        }
        if (break_or_not)
            cout << "+";
        cout << endl;
    }
};
  1. 菜单函数
void menu() {
    cout << "************************************************************************" << endl;
    cout << "                                 页面置换算法                      " << endl;
    cout << "                 1. OPT     2. FIFO     3. LRU      4. 退出      " << endl;
    int choose;
    recin:
    cin >> choose;
    if(choose == 1 || choose == 2 || choose == 3) {
        cout << "请输入页内作业数,最大不超过9:";
        cin >> page_length;
    }
    switch (choose) {
        case 1:
            OPT();
            break;
        case 2:
            FIFO();
            break;
        case 3:
            LRU();
            break;
        case 4:
            cout << "程序正常结束,欢迎再次使用。";
            exit(-1);
        default:
            cout << "输入错误,请重新输入。" << endl;
            goto recin;
    }
}
  1. 3个主要的算法(OPT,FIFO,LRU)
void OPT() {
    page_fault_interrupt = 0;   //初始化缺页中断次数
    cout << "OPT算法页面变化示意图:" << endl;
    for (int i = 0; i < total; i++) {
        if (the_page->getSize() < page_length) {      //1. 页未满
            //输出此时页内容
            the_page->Myprint(1, read[i]);

            the_page->addAtTail(read[i]);
        } else if (the_page->find(read[i]) != -1) {     //2. 页满,该页本来就有这个作业,直接调用即可。
            the_page->Myprint(0, read[i]);
        } else {
            //3. 页满,计算作业调用优先级
            auto *tmp = new MyLinkedList;
            //此for循环退出条件:a. 遍历完毕 b. tmp满了
            for (int j = i + 1; j < total; j++) {     //往后找最后(或不会)调用的作业
                if (the_page->find(read[j]) != -1) {       //该作业需要被调用
                    if (tmp->find(read[j]) == -1) {     //之前没有发现它,直接加在尾部就行
                        tmp->addAtTail(read[j]);
                        if (tmp->getSize() == page_length) {      //tmp满了,说明作业找齐了,退出循环
                            break;
                        }
                    }
                }
            }
            int mark;
            if (tmp->getSize() == page_length) {      //1. tmp满了,置换tmp最后一个
                mark = the_page->find(tmp->get(page_length - 1));
                the_page->deleteAtIndex(mark);
            } else {       //2. tmp未满,置换不在tmp的即可
                for (int j = 0; j < page_length; j++) {
                    if (tmp->find(the_page->get(j)) == -1) {    //tmp的作业找不到就被置换
                        the_page->deleteAtIndex(j);
                        mark = j;
                        break;
                    }
                }
            }
            the_page->addAtIndex(mark, read[i]);
            the_page->Myprint(1, read[i]);
            delete (tmp);       //回收tmp,以免重复使用,内存冲突
        }
    }
    //清一下页面,方便其他算法共用the_page
    delete(the_page);
    the_page = new MyLinkedList;
    cout << "该算法一共发生了 " << page_fault_interrupt << " 次页面置换,缺页中断率为 "
         << page_fault_interrupt / total * 100 << "%" << endl;
}

void FIFO(){
    page_fault_interrupt = 0;   //初始化缺页中断次数
    cout << "FIFO算法页面变化示意图:" << endl;
    for (int i = 0; i < total; i++) {
        if (the_page->getSize() < page_length) {      //1. 页未满
            //输出此时页内容
            the_page->addAtTail(read[i]);
            the_page->Myprint(1, read[i]);
        } else if (the_page->find(read[i]) != -1) {     //2. 页满,该页本来就有这个作业,直接调用即可。
            the_page->Myprint(0, read[i]);
        } else {
            //3. 页满,先进先出

            the_page->deleteAtIndex(0);
            the_page->addAtTail(read[i]);
            the_page->Myprint(1, read[i]);
        }
    }
    //清一下页面,方便其他算法共用the_page
    delete(the_page);
    the_page = new MyLinkedList;
    cout << "该算法一共发生了 " << page_fault_interrupt << " 次页面置换,缺页中断率为 "
         << page_fault_interrupt / total * 100 << "%" << endl;
}

void LRU(){
    page_fault_interrupt = 0;   //初始化缺页中断次数
    cout << "LRU算法页面变化示意图:" << endl;
    //【约定】尾部是最新的
    for (int i = 0; i < total; i++) {
        if (the_page->getSize() < page_length) {      //1. 页未满
            //输出此时页内容
            the_page->addAtTail(read[i]);
            the_page->Myprint(1, read[i]);
        } else if (the_page->find(read[i]) != -1) {     //2. 页满,调换一下顺序,将最新的放尾部
            the_page->deleteAtIndex(the_page->find(read[i]));
            the_page->addAtTail(read[i]);
            the_page->Myprint(0, read[i]);
        } else {
            //3. 页满,将最旧的置换成插入的作业
            the_page->deleteAtIndex(0);     //头部是最旧的
            the_page->addAtTail(read[i]);
            the_page->Myprint(1, read[i]);
        }
    }
    //清一下页面,方便其他算法共用the_page
    delete(the_page);
    the_page = new MyLinkedList;
    cout << "该算法一共发生了 " << page_fault_interrupt << " 次页面置换,缺页中断率为 "
        << page_fault_interrupt / total * 100 << "%" << endl;
}
  1. 读取数据
int read_data(int print_or_not) {
    ifstream in("C:\\Users\\Louis\\Desktop\\project\\CLion_files\\exp7\\data.txt");
    if (!in.is_open()) {
        cout << "路径错误或者文件不存在!";
        exit(1);
    }
    char buffer[256];   //读取文件之用
    in.getline(buffer, 100);
    int j = 0;
    if (print_or_not)
        cout << "页面序列为:";
    int sub = 48;   //"0" - 0 = 48
    for (int i = 0; buffer[i] != '.'; i += 3, j++) {
        read[j] = buffer[i] - sub;
        if (print_or_not)
            cout << "  " << read[j];
    }
    cout << endl;
    return j;   //返回作业数目
}
  1. 主函数
int main() {
    read_data(1);
    while(true){
        menu();
    }
}

data.txt

  • 存放位置
    在这里插入图片描述
  • 内容:(本程序以 “, .” 为结束符分割数据值)
7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1, .

结果:

  • OPT算法
    在这里插入图片描述
  • FIFO算法
    在这里插入图片描述
  • LRU算法
    在这里插入图片描述
完整虚拟存储管理实验报告!一、实验目的请求页式虚存管理是常用的虚拟存储管理方案之一。通过请求页式虚存管理中对页面置换算法的模拟,有助于理解虚拟存储技术的特点,并加深对请求页式虚存管理的页面调度算法的理解。二、实验环境 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值为最小的虚页,将该虚页从装载它的那个实页中置换出去,并在该实页中装入当前正要访问的虚页。~
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Caseythekiwi_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值