文章目录
一、实验目的
存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。本实验的目的是通过请求页式管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。因为源码中我对一些关键步骤的注释已经比较清晰了,所以在本文中不会再对每一个细节都进行分析,只分析整体的代码结构和所使用到的设计模式。
博客内所有文章均为 原创,所有示意图均为 原创,若转载请附原文链接。
二、实验内容
2.1 实现多种页面置换算法并比较算法优劣
-
(1)通过计算不同算法的命中率比较算法的优劣。同时也考虑了用户内存容量对命中率的影响(命中率 = 1 - 页面失效次数 ÷ 页地址流长度)。页面失效次数为每次访问相应指令时,该指令所对应的页不在内存中的次数。在本实验中,假定页面大小为1k,用户虚存容量为32k,用户内存容量为4页到32页。
-
(2)produce_addstream 通过随机数产生一个指令序列,共320条指令。
A、指令的地址按下述原则生成:
1)50%的指令是顺序执行的
2)25%的指令是均匀分布在前地址部分
3)25%的指令是均匀分布在后地址部分
B、具体的实施方法是:
1)在[0,319]的指令地址之间随机选取一起点m;
2)顺序执行一条指令,即执行地址为m+1的指令;
3)在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’;
4)顺序执行一条指令,地址为m’+1的指令
5)在后地址[m’+2,319]中随机选取一条指令并执行;
6)重复上述步骤1)~5),直到执行320次指令
C、将指令序列变换称为页地址流
在用户虚存中,按每k存放10条指令排列虚存地址,即320条指令在虚存中的存放方式为:
第0条~第9条指令为第0页(对应虚存地址为[0,9]);
第10条~第19条指令为第1页(对应虚存地址为[10,19]);
。。。。。。
第310条~第319条指令为第31页(对应虚存地址为[310,319]);
按以上方式,用户指令可组成32页。 -
(3)计算并输出下述算法在不同内存容量下的命中率。
1)最佳置换算法(OPT);
2)先进先出算法(FIFO);
3)最近最久未使用页面置换(LRU);
4)最少使用页面淘汰算法(LFU)
三、流程图
3.1 算法流程
四、设计思想
4.1 设计思路
该实验中需要实现四种页面置换算法,分别为 OPT、FIFO、LRU和LFU,通过分析发现这四种算法中都存在一种优先级的关系,只不过优先级的属性不同,比如在LRU算法中,优先级为最近一次访问距离现在的时间,即页面最近一次访问距离现在的时间越短其优先级越高,而对于LFU算法,优先级页面被访问的次数,即用户内存中页面被访问的次数越多,其优先级也就越高,越不容易被淘汰,而FIFO算法中的优先级就是进入用户空间的时间,时间越短优先级越高,OPT中的优先级就是页面下次被访问据当前的时间,时间越短优先级越高。
当我们找到了这几种算法中的优先级关系后,通过分析可以发现优先级队列可以很好的满足这个需求,而对于LRU算法的实现其实最简单的方法是如果被访问的页面存在于用户空间中,那么就将其提升至队尾(队尾入页面,队头出页面),但是为了保证多个算法的统一性,还是决定采用相同的抽象算法来实现。
而对于整体的代码结构设计,可以采用 模板方法设计模式 + 策略设计模式 的方法来进行实现,增强算法整体的灵活性、可扩展性和可维护性。
4.2 代码分析
首先是Page结构体,该结构体保存了 OPT、LRU 和 LFU 算法所需的各项属性。
struct Page
{
Page() : elapsed_time_since_last_visit(0), used_count(0) {
}
int virtual_memory_index;
// OPT
TimeSlice be_used_again_time_;
// LRU
TimeSlice elapsed_time_since_last_visit;
// LFU
int used_count;
};
其次是 UserMemorySpace 类,该类是用户内存空间的抽象,提供了一个模板参数 PriorityCmp,用来指定优先级队列中的优先级关系定义,并且在它的属性中存在 page_index_array_ 数组和 memory_queue_优先级队列,其中前者是保存所有的虚拟页面信息,PageInfo 中持有 Page 的引用,同时记录该页面是否存在于用户空间优先级队列中,而后者的 memory_queue_ 就是物理用户内存空间,前者的存在主要是了便于对物理用户内存空间内页面的查找定位,而该类的功能总结起来就是提供了对物理用户内存空间的基础操作(确定一个页面是否存在于用户空间中,获取一个页面,插入一个页面等等)。
template<typename PriorityCmp>
class UserMemorySpace
{
public:
struct PageInfo
{
bool in_user_memory = false;
PagePtr page = new Page();
};
typedef PageInfo * PageInfoPtr;
UserMemorySpace(int user_memory_size, int virtual_memory_size)
: user_memory_size_(user_memory_size)
, virtual_memory_size_(virtual_memory_size)
, memory_queue_(new std::priority_queue<PagePtr, std::vector<PagePtr>, PriorityCmp>())
, page_index_array_(new std::vector<PageInfoPtr>(virtual_memory_size));
inline void initPageIndexArray();
void push(int virtual_page_index);
PagePtr pop();
inline PageInfoPtr getPageInfo(int virtual_page_index);
inline PagePtr getPage(int virtual_page_index);
inline bool pageInUserMemory(int virtual_page_index);
void freshPageOrder();
std::vector<PagePtr> * getPagesInUserMemory();
private:
int user_memory_size_;
int virtual_memory_size_;
// help find page in memory queue
std::vector<PageInfoPtr> * page_index_array_;
std::priority_queue<PagePtr, std::vector<PagePtr>, PriorityCmp> * memory_queue_;
};
接下来是页面置换算法,这里采用了模板方法设计模式,其中PageReplacementAlgorithm为所有是算法的抽象基类,不提供具体实现,只规定算法所必须实现的方法,且其持有一个UserMemorySpace的引用。
// 页面置换算法基类
class PageReplacementAlgorithm;
// 最佳页面置换算法
class OPTPageReplacementAlgorithm : public PageReplacementAlgorithm;
// 先来先服务页面置换算法
class FIFOPageReplacementAlgorithm : public PageReplacementAlgorithm;
// LRU 页面置换算法
class LRUPageReplacementAlgorithm : public PageReplacementAlgorithm;
// LFU 页面置换算法
class LFUPageReplacementAlgorithm : public PageReplacementAlgorithm;
最后两个模块类,PageReplacement是对页面置换逻辑的封装,主要用于聚合PageReplacementAlgorithm和UserMemorySpace,并设置相应的物理用户内存空间的大小,而PageReplacementWrapper是对PageReplacement的进一步封装,指引用户输入相应的数据(具体实现请见源码)。
template<typename PageReplacementAlgorithm, typename PriorityCmp>
class PageReplacement;
class PageReplacementWrapper;
五、代码实现
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <cstdlib>
#include <ctime>
#include <unistd.h>
#include <iomanip>
class Util
{
public:
static inline int getRandom(const int min_val, const int max_val, int match)
{
srand(time(0) + match);
return ((max_val - min_val - 1) == 0) ? min_val : rand() % (max_val - min_val - 1) + min_val;
}
};
typedef int TimeSlice;
int page_replacement_count = 0;
std::vector<double> * ratio = new std::vector<double>(28, 0);
struct Page
{
Page() : elapsed_time_since_last_visit(0), used_count(0) {
}
int virtual_memory_index;
// OPT
TimeSlice be_used_again_time_;
// LRU
TimeSlice elapsed_time_since_last_visit;
// LFU
int used_count;
};
typedef Page * PagePtr;
template<typename PriorityCmp>
class UserMemorySpace
{
public:
struct PageInfo
{
bool in_user_memory = false;
PagePtr page = new Page();
};
typedef PageInfo * PageInfoPtr;
UserMemorySpace(int user_memory_size, int virtual_memory_size)
: user_memory_size_(user_memory_size)
, virtual_memory_size_(virtual_memory_size)
, memory_queue_(new std::priority_queue<PagePtr, std::vector<PagePtr>, PriorityCmp>())
, page_index_array_(new std::vector<PageInfoPtr>(virtual_memory_size))
{
initPageIndexArray();
}