广州大学2022操作系统实验三——内存管理


一、实验内容

1、模拟实现请求页式存储管理的几种基本页面置换算法
(1)最佳淘汰算法(OPT)
(2)先进先出的算法(FIFO)
(3)最近最久未使用算法(LRU))

二、实验原理

1、虚拟存储系统
UNIX中,为了提高内存利用率,提供了内外存进程对换机制;内存空间的分配和回收均以页为单位进行;一个进程只需将其一部分(段或页)调入内存便可运行;还支持请求调页的存储管理方式。
当进程在运行中需要访问某部分程序和数据时,发现其所在页面不在内存,就立即提出请求(向CPU发出缺中断),由系统将其所需页面调入内存。这种页面调入方式叫请求调页。
为实现请求调页,核心配置了四种数据结构:页表、页框号、访问位、修改位、有效位、保护位等。

2、页面置换算法
当CPU接收到缺页中断信号,中断处理程序先保存现场,分析中断原因,转入缺页中断处理程序。该程序通过查找页表,得到该页所在外存的物理块号。如果此时内存未满,能容纳新页,则启动磁盘I/O将所缺之页调入内存,然后修改页表。如果内存已满,则须按某种置换算法从内存中选出一页准备换出,是否重新写盘由页表的修改位决定,然后将缺页调入,修改页表。利用修改后的页表,去形成所要访问数据的物理地址,再去访问内存数据。整个页面的调入过程对用户是透明的。
(1)最佳淘汰算法(OPT):选择永不使用或在未来最长时间内不再被访问的页面予以替换。
(2)先进先出的算法(FIFO):选择在内存中驻留时间最久的页面予以替换。
(3)最近最久未使用算法(LRU):选择过去最长时间未被访问的页面予以替换。

3、首先用srand( )和rand( )函数定义和产生指令序列,然后将指令序列变换成相应的页地址流,并针对不同的算法计算出相应的命中率。
(1)通过随机数产生一个指令序列,共320条指令。指令的地址按下述原则生成:
A:50%的指令是顺序执行的
B:25%的指令是均匀分布在前地址部分
C:25%的指令是均匀分布在后地址部分
具体的实施方法是:
A:在[0,319]的指令地址之间随机选取一起点m
B:顺序执行一条指令,即执行地址为m+1的指令
C:在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’
D:顺序执行一条指令,其地址为m’+1
E:在后地址[m’+2,319]中随机选取一条指令并执行
F:重复步骤A-E,直到320次指令
(2)将指令序列变换为页地址流
设:页面大小为1K;
用户内存容量4页到32页;
用户虚存容量为32K。
在用户虚存中,按每K存放10条指令排列虚存地址,即320条指令在虚存中的存放方式为:
第 0 条-第 9 条指令为第0页(对应虚存地址为[0,9])
第10条-第19条指令为第1页(对应虚存地址为[10,19])
………………………………
第310条-第319条指令为第31页(对应虚存地址为[310,319])
按以上方式,用户指令可组成32页。

因为是模拟程序,可以不使用系统调用函数

三、实验步骤

1.画出每个页面置换算法流程图

S=MAX(320)

OPT:

在这里插入图片描述
LRU也是这样的流程,不同的地方是Ofar函数不同

Ofar()流程图:

P=start(图写错了)
Far算法是变量内存数组,然后寻找距离最远的数,目的是更新或使最远页数在内存中的下标值,然后返回这个需要更改的下标值

在这里插入图片描述

Lfar()流程图:

Lfar的流程,只改变了distance计算方法和p的移动方向

在这里插入图片描述

FIFO:

在这里插入图片描述

2.对算法所用的数据结构进行说明:

数组说明:
在这里插入图片描述在这里插入图片描述
随机生成320条指令函数:
在这里插入图片描述
cpage():

将随机指令转换成页地址流的函数

在这里插入图片描述
find():

判断页是否在内存中 其实是一个查找数num是否在参数数组内的一个函数

在这里插入图片描述
Ofar():

在OPT算法中寻找最久未使用或未来不使用的内存内的页号的下标

在这里插入图片描述
Lfar():

LRU算法中寻找最近最久未使用的内存内的页号的下标

这里加入LRU算法中的查找所需下标的函数,因为两个函数很像,只是查找方向相反

在这里插入图片描述
LRU算法实现

在这里插入图片描述
OPT算法实现

和上图一样,因为这部分函数主要是判断指针所指的页号是否在内存,并调用查找需要替换的内存下标并进行替换

在这里插入图片描述
FIFO算法实现
在这里插入图片描述

3. 测试数据随机产生。不可手工输入:

在这里插入图片描述

4.多次测试程序,截屏输出实验结果:

OPT

因为320,32,不易观察,下图数据暂时修改成150和15
只显示发生缺页中断时的页地址流和内存表

在这里插入图片描述

LRU

因为320,32,不易观察,下图数据暂时修改成150和15
只显示发生缺页中断时的页地址流和内存表

在这里插入图片描述

FIFO

在这里插入图片描述

出现该问题的原因: 首次构造链表算法写错了,改成后插法就可以了(为了记录问题所以没有更改) 在这里插入图片描述
第一次输出出问题原因在于我算法是先将内存表填满,FIFO算法内存表用了链表,在第一次构建链表的时候没有用后插法创建链表,有问题的算法为:
在这里插入图片描述
过程为先赋值p->data,在创建新结点,p后移,但是这样的问题是当最后一个数赋值后,后面还是会连着一个data为空的新结点,导致在print的时候p指向最后一个数据时p->next不为NULL(指向空结点,空结点next为NULL)
但是不影响后面的算法,因为last指向是正确的

5.根据实验结果与理论课讲述的原理进行实验分析

OPT算法页号命中率:

在这里插入图片描述

LRU算法页号命中率:
在这里插入图片描述在这里插入图片描述

输出LRU命中率会出现只输出一部分从内存大小最小值开始的命中率的问题(如只输出内存4k到17k就停下来了)通过更改内存大小的区间(如设置18k-31k)才得到内存由4k-31k的命中率,所以上面的结果图是运行了两次然后截图的
( 另外两个就不会,我也不知道为什么😔)

FIFO算法命中率

在这里插入图片描述在这里插入图片描述

五、实验数据及源代码

写了很多输出语句用于判断算法是否正确,可以忽略

#include <iostream>
#include <ctime>
#include <iomanip>
using namespace std;
#define MAX 320
#define MAX2 32
void create(int sequence[])
{
	int i = 0;//计数器
	while (1)
	{
		if (i == MAX)break;
		int m = rand() % MAX;
		sequence[i++] = m++;//执行m+1
		m = rand() % m;//在前地址[0,m+1]中随机选取一条指令并执行
		if (i == MAX)break;
		sequence[i++] = m;//执行m'
		if (i == MAX)break;
		sequence[i++] = ++m;//执行m'+1
		m = rand() % MAX + (m+1);
		if (i == MAX)break;
		sequence[i++] = m;//执行后地址中随机指令
	}
	cout << "指令生成成功" << endl;

}
static int s = MAX;//页地址流最大长度
void cpage(int sequence[MAX], int page[MAX])
{
	int i=0,j;
	while (i < MAX)
	{
		j = sequence[i] / 10;//求页号
		page[i] = j;
		i++;
	}
}
int find(int pnum, int caqa[MAX2],int sum)//页是否在内存
{
	int flag = 0;
	for (int i = 0; i < sum;i++)
	{
		if (pnum == caqa[i]) { flag = 1; break; }
		flag = 0;
	}
	return flag;
}
void print(int A[],int sum)//数组输出函数
{
	for (int i = 0; i < sum; i++)
		cout << A[i] << " ";
}
void printhit(double A[], double Asum[],int ckind)//数组输出函数
{
	for (int i = 0; i < ckind; i++)
	{
		if(A[i]!=NULL)
		cout << "page" << i << " 命中率:"<< A[i]/Asum[i] << endl;
	}
}

int Ofar(int page[MAX], int caqa[MAX2], int sum, int start)
{
	int p = start;
	int i = 0;
	int index;
	int distance = 0;
	while (i<sum)
	{
		if (caqa[i] != page[p])p++;
		else {
			index = distance < p - start ? i : index;
			distance = distance < p - start ? p - start : distance;
			i++; p = start;
		}
		if (p == s + 1) { index = i; break; }//如果p到了最后还没找到,则说明是不被使用的老页面
	}
	return index;
}
void OPT(int page[MAX],int caqa[MAX2],int sum)
{
	double falsehit = 0;
	int ckind = 1;//页地址流的总页类数
	int change;
	int ci = 0;
	for (int i = 0; i < MAX;i++)
	{
		if (!find(page[i], caqa, sum))
			caqa[ci++] = page[i];
		if (ci ==sum)break;
	}//填充
	int p = sum;//p指向当前位置
	while (p < s)//页号小于页地址最大长度时
	{
		if (!find(page[p], caqa, sum))//缺页中断(page不在caqa里)
		{
			falsehit++;//缺页次数+1;
			change = Ofar(page, caqa, sum, p);//替换的数组下标
			/*print(page, s); cout << "\n";cout << "缺页中断! 需要页号:" << page[p] << endl;cout << "原内存表:";print(caqa, sum); cout << "\n";cout << "替换的页:" << caqa[change] << endl;*/
			caqa[change] = page[p];//替换后p指针后移
			/*cout << "内存表:";
			print(caqa, sum); cout << "\n";*/
		}
		p++;
	}
	cout << "内存大小" << sum <<"k" << " 命中率:" << 1 - (falsehit / MAX) << endl;
	
}
//先进先出用链表
typedef struct LNode
{
	int data;//存放页号
	struct LNode* next;
}*LinkList;
int Ffind(LinkList& L,int num)//寻找num在不在链表里
{
	int flag = 0;
	auto p = L;
	while (p != NULL)
	{
		if (p->data == num) { flag = 1; break; }
		p = p->next;
	}
	return flag;
}
void printL(LinkList& L)
{
	auto p = L;
	while (p!= NULL)
	{
		cout << p->data << "-> ";
		p = p->next;

	}
	cout << "\n";
}
void FIFO(int page[MAX], int caqa[MAX2], int sum)
{
	LinkList L;
	double falsehit = 0;
	L = new LNode;
	L->next = NULL;
	auto head = L;
	auto p = head;
	int i = 0, j = 0;//j相当于在页地址流移动的快指针
	while (i<sum)//填充
	{
		
		//如果j所指的页号不在链表
		if (!Ffind(L, page[j])) { p->data = page[j]; auto temp = new LNode; temp->next = NULL; p->next = temp; p = p->next; p->next = NULL; i++;}
		j++;
		
	}
	j = sum;
	auto last = head;
	while (last->next->next != NULL)
		last = last->next;
	
	while (j<s)
	{
		if (!Ffind(head, page[j]))
		{
			falsehit++;
			/*print(page, s); cout << "\n";cout << "缺页中断! 需要页号:" << page[j] << endl;cout << "原内存表:";printL(head);*/
			auto newhead = head->next; head->next = NULL; head = newhead;
			auto temp = new LNode; temp->next = NULL; temp->data = page[j];
			last->next = temp; last = last->next; last->next = NULL;
			/*cout << "修改后内存表:";
			printL(head);*/
		}
		j++;
	}
	cout << "内存大小" << sum << "k" << " 命中率:" << 1 - (falsehit / MAX) << endl;
}
int Lfar(int page[MAX], int caqa[MAX2], int sum, int start)
{
	int p = start-1;
	int i = 0;
	int index;
	int distance = 0;
	while (i < sum)
	{
		if (caqa[i] != page[p])p--;
		else {
			index = distance < start - p ? i : index;
			distance = distance < start - p ? start - p : distance;
			i++; p = start-1;
		}
	}
	return index;
}
void LRU(int page[MAX], int caqa[MAX2], int sum)
{
	double falsehit = 0;
	int change;
	int ci = 0;
	for (int i = 0; i < MAX; i++)
	{
		if (!find(page[i], caqa, sum))
			caqa[ci++] = page[i];
		if (ci == sum)break;
	}//填充
	//print(caqa, sum);
	int p = sum;//p指向当前位置
	while (p < s)//页号小于页地址最大长度时
	{
		if (!find(page[p], caqa, sum))//缺页中断(page不在caqa里)
		{
			falsehit++;//缺页次数+1;
			change = Lfar(page, caqa, sum, p);//替换的数组下标

			/*print(page, s); cout << "\n";
			cout << "缺页中断! 需要页号:" << page[p] << endl;
			cout << "原内存表:";
			print(caqa, sum); cout << "\n";
			cout << "替换的页:" << caqa[change] << endl;*/

			caqa[change] = page[p];//替换后p指针后移
			/*cout << "内存表:";
			print(caqa, sum); cout << "\n";*/
			
		}
		p++;
	}
	cout << "内存大小" << sum << "k" << " 命中率:" << 1 - (falsehit / MAX) << endl;
}
int main()
{
	srand((unsigned long)time(0));
	int sequence[MAX]{};//指令序列
	int page[MAX]{};//页地址流
	int capacity = rand() % (MAX2-4+1) + 4;//随机内存
	int caqa[MAX2];//内存
	create(sequence);
	cpage(sequence,page);
	//OPT(page, caqa, capacity);
	//LRU(page, caqa, capacity);
	//FIFO(page, caqa, capacity);
}

总结

  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值