您的位置:首页 > 其它

5种页面置换算法的实现

2016-05-28 00:57 169 查看
前几天做了一个有关页面替换算法的题,要求如下:

1
简介
要求实现多种页面替换算法,然后利用随机产生的引用串测试其性能。
2
页面替换算法
   我们做如下假设:
• 虚拟内存页面总数为P,标号从0到P−1;
• 引用串RS(reference string)是一个整数序列,整数的取值范围为0到P−1。RS中的每个元素p表示对页面p的一次引用;
• 物理内存由F帧组成,标号从0到F−1。我们引入一个数组M[F], 数组元素M[f]中包含数字p,它表示帧f中包含页面p。页面替换算法顺次读取RS中的每个元素。对于RS中的元素值p,算法搜索数组M[F],判断是否存在某个f,使得M[f]
== p。如果未发现,则表示页面缺失。这时,算法必须根据其特定的替换规则,选择一帧M[i],用页面p替换其中的内容,即令M[i] = p。
   下面讨论各种替换算法所需要的不同数据结构:
• 最佳替换算法和随机替换算法不需要其它的数据结构。 对于最佳替换 算法,通过搜索RS即足以确定应被替换的页面;对于随机替换算法,产生一个取值范围在0和F−1之间的随机数,该随机数即可表示应被替换的页面。
• FIFO需要一个指向最老页面的指针(数组索引)。每当该页面被替换的时候,把该指针加1(模F)即可。
• LRU算法则需要一个尺寸为F的数组,该数组用来实现排队功能:每次处理一个新的页面引用时,则把该页放置在队列的末尾。这样, 每当需要淘汰一个页面时,从队首取到的即最长时间未被用到的页面。
• Clock算法(也叫second−chance算法)和FIFO算法一样,需要一个指针。此外,它还需要一个数组,用来记录每一帧的使用情况。

   本实验要求实现多种页面替换算法,然后利用随机产生的引用串测试其性能。
3
引用串的生成
   实现了页面替换算法以后,我们还需要生成引用串,用以测试页面替换算法的性能。生成引用串的关键在于如何模拟程序的局部性。
生成不带局部性的引用串最为容易, 遗憾的是, 这和绝大多数的程序特性不符。多数程序都显示出高度的局部性,也就是说,在一个时间内,一组页面被反复引用。

 
 这组被反复引用的页面随着时间的推移,其成员也会发生变化。有时这种变化是剧烈的,有时这种变化则是渐进的。我们把这组页面的集合称 为当前工作集。

 
 我们可以为程序的这种行为方式建立如下模型。首先,我们定当前工作集由虚拟内存中连续的页面组成。这当然与实际情况不符,因为程序的代码、数据和堆栈通常分处在不同的虚拟内存区域。但是,对于研究页面替换算法来说,我们关心的只是当前工作集的大小,以及其成员更替的频繁程度。因此,从这个意义上说,我们的假设是合理的。
   我们进一步假设引用在当前工作集内的分布是均匀的。工作集可用其起始页面,以及其中包含的页面数表示。 随着时间的推移,工作集在虚拟内存中不断移动。有时,这种移动是渐进的,而有时则是剧烈的。为了给渐进移动建立模型,我们做如下假设:

工作集在固定的方向向匀速前进(例如,在处理了m个引用后,把工作集的起始页面加1)。对于剧烈移动,我们则重新随机选择工作集的起始页面
即可。剧烈移动在整个移动中的比率,我们用t表示。根据以上假设,引用串可用如下算法产生:
1. 确定虚拟内存的尺寸P,工作集的起始位置p,工作集中包含的页数e,工作集移动率m,以及一个范围在0和1之间的值t;
2. 生成m个取值范围在p和p+e间的随机数,并记录到引用串中;
3. 生成一个随机数r,0
≤r
≤1;
4. 如果r<t,则为p生成一个新值,否则p = (p+1) mod P;
5. 如果想继续加大引用串的长度,请返回第而2步,否则结束。
4
性能评测
测试不同的引用串以及不同的虚拟内存尺寸

我把页面置换算法封装起来了,引用串的生成函数放在了main函数的上面,先贴封装的算法类:

头文件如下:#ifndef __ALG__
#define __ALG__

#include <vector>
#include <iostream>
#include <time.h>

using namespace std;

enum Strategy
{
OPT = 0, //最佳置换算法
RPA, //随机置换算法
FIFO, //先进先出算法
LUR, //最近最久未使用算法
CLOCK //时钟算法
};

class NodeForLUR
{
public:
NodeForLUR() {}
~NodeForLUR() {}

int index;
NodeForLUR* next;
};

class LinkForLUR
{
public:
LinkForLUR() {}
~LinkForLUR() {}

NodeForLUR* head;
NodeForLUR* tail;
};

class Algorithms
{
public:
explicit Algorithms(int memory_size);
~Algorithms();

void setReferenceString(std::vector<int> rs);
int exePageReplace(Strategy strategy);

private:
void resetMemory();
int OPT(int current_serial);
int RPA();
int FIFO();
int LUR();
void updateLinkForLUR(int index);
void deleteLinkForLUR(NodeForLUR* node);
int CLOCK();

//int page_size;
int memory_size;
int memory_used;
int oldest_index;
LinkForLUR link_for_LUR;
int *memory; //模拟物理内存
bool *clock;
int placement_count;//置换次数
std::vector<int> reference_string;
};

#endif // !__ALG__
CPP文件如下:

#include "stdafx.h"

Algorithms::Algorithms(int memory_size)
{
this->memory_size = memory_size;
this->memory_used = 0;
this->memory = new int[memory_size];
this->clock = new bool[memory_size];
this->link_for_LUR.head = nullptr;
this->link_for_LUR.tail = nullptr;
this->oldest_index = 0;
this->placement_count = 0;
}

void Algorithms::setReferenceString(std::vector<int> rs)
{
this->reference_string.clear();
this->reference_string = rs;
}

int Algorithms::exePageReplace(Strategy strategy)
{
//检测引用串的设置情况
if (reference_string.empty()) {
std::cout << "ERROR:引用串未设置!" << endl;
return -1;
}

//检测是否初始化内存使用
if (0 != memory_used) {
resetMemory();
}

vector<int>::iterator ir = reference_string.begin();
for (; ir < reference_string.end(); ++ir) {

//是否物理内存中已存在该页面
int index;
for (index = 0; index < memory_used; index++) {
if (memory[index] == *ir) {
break;
}
}
if (index != memory_used) {
//内存存在
//std::cout << "引用串第" << ir - reference_string.begin() << "位已存在物理内存中!" << endl;
if (strategy == Strategy::LUR) {//策略为LUR时,更新最近最久未使用队列
updateLinkForLUR(index);
}
else if (strategy == Strategy::CLOCK) {
clock[index] = true;
oldest_index = (index + 1) % memory_size;
}
continue;
}

//是否有空闲内存
if (memory_used < memory_size) {
memory[memory_used++] = *ir;
//std::cout << "引用串第" << ir - reference_string.begin() << "位已加入空闲物理内存中!" << endl;
if (strategy == Strategy::LUR) {//策略为LUR时,增加最近最久未使用队列节点
if (memory_used == 1) {
link_for_LUR.head = new NodeForLUR();
link_for_LUR.head->index = 0;
link_for_LUR.tail = link_for_LUR.head;
}
else {
auto temp_node = new NodeForLUR();
temp_node->index = memory_used - 1;
temp_node->next = link_for_LUR.head;
link_for_LUR.head = temp_node;
}
}
else if (strategy == Strategy::CLOCK) {
clock[memory_used - 1] = true;
}
continue;
}

//无空闲内存,页面替换
int page;
placement_count++;
switch (strategy)
{
case Strategy::OPT:
{
int current_serial = ir - reference_string.begin();
page = OPT(current_serial);
break;
}
case Strategy::RPA:
page = RPA();
break;
case Strategy::FIFO:
page = FIFO();
oldest_index = (oldest_index+1)%memory_size;
break;
case Strategy::LUR:
page = LUR();
updateLinkForLUR(page);
break;
case Strategy::CLOCK:
page = CLOCK();
clock[page] = true;
break;
default:
_ASSERTE(0);
}
//cout << strategy <<" page :" << page << endl;
memory[page] = *ir;
}
return placement_count;
}

/*
重置内存使用
*/
void Algorithms::resetMemory()
{
std::cout << "内存使用未重置,正在重置!" << endl;
while (--memory_used >= 0)
{
memory[memory_used] = 0;
}
if (link_for_LUR.head != nullptr) {
deleteLinkForLUR(link_for_LUR.head);
link_for_LUR.head = nullptr;
link_for_LUR.tail = nullptr;
}
memory_used++;
oldest_index = 0;
placement_count = 0;
}

/*
最佳页面替换算法,返回替换页面在物理内存中的序号,下同
*/
int Algorithms::OPT(int current_serial)
{
//分析是否有某个页面后续永不使用
int memory_index = 0, MAX_PAGE = -1, MAX_COUNT = -1;
for (; memory_index < memory_size; memory_index++)
{
int rs_index;
for (rs_index = current_serial; rs_index < reference_string.size(); ++rs_index) {
if (memory[memory_index] == reference_string[rs_index]) {
if (MAX_COUNT < rs_index) {//当前页面在未来将会被再次引用,记录引用位置和页面号
MAX_PAGE = memory_index;
MAX_COUNT = rs_index;
}
break;
}
}
if (rs_index == reference_string.size()) {//找到可替换页面(存在某页面永不使用)
return memory_index;
}
}

//无页面永不使用,则返回最长时间不使用页面在物理内存中的序号
return MAX_PAGE;
}

/*
随机置换页面算法
*/
int Algorithms::RPA()
{
return rand()%memory_size;
}

/*
先进先出算法
*/
int Algorithms::FIFO()
{
return oldest_index;
}

int Algorithms::LUR()
{
return link_for_LUR.tail->index;
}

void Algorithms::updateLinkForLUR(int index)
{
//移动节点
auto temp_node = link_for_LUR.head;
NodeForLUR* last_node = nullptr;
while (temp_node->index != index)
{//查找节点
_ASSERT(temp_node != nullptr);
last_node = temp_node;
temp_node = temp_node->next;
}
if (temp_node == link_for_LUR.head) {//如果查找到的节点是头结点,则无改动退出。
return;
}
if (temp_node == link_for_LUR.tail && last_node != nullptr) {//是否是尾节点且链长大于1
link_for_LUR.tail = last_node;
}
last_node->next = temp_node->next;
temp_node->next = link_for_LUR.head;
link_for_LUR.head = temp_node;
}

/*
用于删除LUR的链表
*/
void Algorithms::deleteLinkForLUR(NodeForLUR* node)
{
if (node->next != nullptr) {
deleteLinkForLUR(node->next);
delete node;
node = nullptr;
}
else {
delete node;
node = nullptr;
}
}

/*
这里借用了FIFO算法的oldest_index游标。反正一个策略执行完也会重置。
*/
int Algorithms::CLOCK()
{
//查看是否有访问位为0的
for (int index = oldest_index; index < memory_size; index++)
{
if (!clock[index]) {
oldest_index = (index + 1) % memory_size;
return index;
}
else{
clock[index] = false;
}
}
oldest_index = 0;
return CLOCK();
}

Algorithms::~Algorithms()
{
delete[] memory;
delete[] clock;
memory = nullptr;
if (link_for_LUR.head != nullptr) {
deleteLinkForLUR(link_for_LUR.head);
}
}


main函数所在文件如下:

#include "stdafx.h"

#define _SCALE_ 100
/*
函数功能:用于生成引用串
参数从左至右依次为:
v:用于填充的引用串
page_size:页面总数P
set_num:工作集中包含的页数e
move:工作集移动率m
jitter_rate:抖动率
rs_size:预期生成的引用串长度
*/
void genReferenceString(vector<int>& v, int page_size, int set_num,
int start_position, int move, float jitter_rate, int rs_size) {

int length = 0;
srand((int)time(0));
while (length < rs_size)
{
for (int count = 0; count < move; count++) {
v.push_back((start_position + rand() % set_num)% page_size);
length++;
}
int r = rand() % _SCALE_;
if (r < jitter_rate*_SCALE_) {
cout << "发生抖动,抖动位置为 " << length << endl;
start_position = rand() % page_size;
}
else
{
start_position = (start_position + 1) % page_size;
}
}
}

int main()
{
Algorithms test(10);
vector<int> rs;
genReferenceString(rs, 100, 10, 0, 10, 0.3, 40);
cout << "此次随机生成的引用串如下所示!" << endl;
for (int index = 0; index < 40; index++) {
cout << "\t" << rs[index] ;
if (index % 5 == 4) {
cout << endl;
}
}
Strategy strategy[] = { Strategy::OPT, Strategy ::RPA, Strategy::FIFO, Strategy::LUR, Strategy::CLOCK};
test.setReferenceString(rs);
for (int index = 0; index < 5; ++index) {
cout << "第" << index << "号策略:" << endl;
cout << "共计交换页面" << test.exePageReplace(strategy[index]) << "次!" << endl;
}
return 0;
}


stdafx.h文件里我放了这么一句,所以要包含一下:
#include "Algorithms.h"


程序的注释也很详细,我就不做过多解释了。有问题可以私信问我。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 页面置换 性能