5种页面置换算法的实现

前几天做了一个有关页面替换算法的题,要求如下:

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


程序的注释也很详细,我就不做过多解释了。有问题可以私信问我。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值