16281053_杨瑷彤_操作系统第四次实验

16281053_杨瑷彤_操作系统第四次实验
源代码链接:https://github.com/rdjyat/operating-system/tree/master/操作系统实验四

1. 实验目的

设计和实现最佳置换算法、先进先出置换算法、最近最久未使用置换算法、页面缓冲置换算法;
通过页面访问序列随机发生器实现对上述算法的测试及性能比较。

2. 实验说明

模拟的虚拟内存的地址为16位,页面大小为1K
模拟的物理内存有32K
页表用整数数组或结构数组来表示
页面访问序列串是一个整数序列,整数的取值范围为0到N - 1。页面访问序列串中的每个元素p表示对页面p的一次访问

页面访问序列随机生成:
符合局部访问特性的随机生成算法
确定虚拟内存的尺寸N,工作集的起始位置p,工作集中包含的页数e,工作集移动率m(每处理m个页面访问则将起始位置p +1),以及一个范围在0和1之间的值t;
生成m个取值范围在p和p + e间的随机数,并记录到页面访问序列串中;
生成一个随机数r,0 ≤ r ≤ 1;
如果r < t,则为p生成一个新值,否则p = (p + 1) mod N;
如果想继续加大页面访问序列串的长度,请返回第2步,否则结束。

性能测评:
测试不同的页面访问序列及不同的虚拟内存尺寸,并从缺页率、算法开销等方面对各个算法进行比较。(同时请给出在给定页面访问序列的情况下,发生页面置换次数的平均值)

3.实验设计

3.1 页面访问序列串随机生成
3.1.1 算法设计
1) 确定虚拟内存的尺寸N,工作集的起始位置p,工作集中包含的页数e,工作集移 动率m(每处理m个页面访问则将起始位置p +1),以及一个范围在0和1之间 的值t;
2) 生成m个取值范围在p和p + e间的随机数,并记录到页面访问序列串中;
3) 生成一个随机数r,0 ≤ r ≤ 1;
4) 如果r < t,则为p生成一个新值,否则p = (p + 1) mod N;
5) 如果想继续加大页面访问序列串的长度,请返回第2步,否则结束。

3.1.2 算法流程图
在这里插入图片描述
代码:

void getPageAccessSequence() {
	double t = 0.6;
	int sum = 0;
	int i;
	while (sum + m <= lengthOfSequence) {
		for (i = 0; i<m; i++) {
			workingSet[sum + i] = (rand() % e + p) % N;
		}
		double r = rand()*1.0 / RAND_MAX;
		if (r<t) {
			p = rand() % N;
		}
		else {
			p = (p + 1) % N;
		}
		sum += m;
	}
}

3.2 最佳置换算法
3.2.1 基本思想
选择永不使用或是在最长时间内不再被访问(即距现在最长时间才会被访问)的页面淘汰出内存。
1、当物理块未满时,按物理块号大小遍历,寻找空闲物理块。
2、当物理块满,需进行替换时,初始化各物理内存块最近访问排名(为语言所支持的最大值)。通过遍历剩余访问序列,确定每个物理块中所存放的逻辑块最近会被访问的排名。找出排名最大的物理块作为替换。

3.2.2 算法流程图

在这里插入图片描述
代码:

int optimal(int index) {
	int number = workingSet[index];
	int i;
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == -1) {
			mm[i] = number;
			return 1;
		}
	}
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == number)
			return 1;
	}

	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		visit[i] = 0;
	}
	int count = 0;
	for (i = index + 1; i<lengthOfSequence; i++) {
		int x = workingSet[i];
		int j;
		for (j = 0; j<(sizeof(mm) / sizeof(mm[0])); j++) {
			if (mm[j] == x) {
				if (visit[j] == 0) {
					visit[j] = 1;
					count++;
					if (count == (sizeof(mm) / sizeof(mm[0])) - 1) {
						break;
					}
				}
				break;
			}
		}
		if (count == (sizeof(mm) / sizeof(mm[0])) - 1) {
			break;
		}
	}
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (visit[i] == 0) {
			mm[i] = number;
			return 0;
		}
	}
	return 0;
}

3.3 先进先出置换算法
3.3.1 基本思想
(1)选择最先进入内存即在内存驻留时间最久的页面换出到外存
(2)进程已调入内存的页面按进入先后次序链接成一个队列,并设置替换指针以指向最老页面
3.3.2 算法流程图
在这里插入图片描述
代码:

int fifo(int index) {
	int number = workingSet[index];
	int i;
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == -1) {
			mm[i] = number;
			return 1;
		}
	}
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == number)
			return 1;
	}


	mm[pointer] = number;
	pointer = (pointer + 1) % (sizeof(mm) / sizeof(mm[0]));
	return 0;
}

3.4 最近最久未使用置换算法
3.4.1 基本思想
以“最近的过去”作为“最近的将来”的近似,选择最近一段时间最长时间未被访问的页面淘汰出内存。
1、通过设置一个物理块访问的动态数组,每次访问,如果待访问的物理块在动态数组中,则把其移到数组尾部;
2、如果不在,当物理块未满时,按物理块号大小遍历,寻找空闲物理块。
3、如果不在,当物理块满时,将动态数组的头部的物理块选为替换块。
3.4.2 算法流程图
在这里插入图片描述代码:

int LRU(int index) {
	int number = workingSet[index];
	int i;
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == number) {
			int j = i;
			while (j<(sizeof(mm) / sizeof(mm[0])) && mm[j] != -1)
				j++;
			j--;
			int k;
			for (k = i; k < j; k++) {
				mm[k] = mm[k + 1];
			}
			mm[(sizeof(mm) / sizeof(mm[0])) - 1] = number;
			return 1;
		}

	}
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == -1) {
			mm[i] = number;
			return 1;
		}
	}
	for (i = 0; i < (sizeof(mm) / sizeof(mm[0])) - 1; i++) {
		mm[i] = mm[i + 1];
	}
	mm[(sizeof(mm) / sizeof(mm[0])) - 1] = number;
	return 0;

}

3.5 改进型clock算法
3.5.1 基本思想
1、当物理块未满时,按物理块号大小遍历,寻找空闲物理块。
2、当物理块满时,按物理块号大小,从小到大,扫描循环队列,寻找访问位为假且修改位为假的,将所遇到的第一个作为所选中的淘汰块。
3、如果(2)没找到,则寻找访问位为假且修改位为真的,将所遇到的第一个作为所选中的淘汰块。将所有扫描过的块的访问位都置为0;
4、如果(3)没找到,重复(2)和(3),必定能找到淘汰块。
代码:

int clock(int index) {
	int number = workingSet[index];
	int i;
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == -1) {
			mm[i] = number;
			visit[i] = 1;
			return 1;
		}
	}
	for (i = 0; i<(sizeof(mm) / sizeof(mm[0])); i++) {
		if (mm[i] == number) {
			visit[i] = 1;
			return 1;
		}
	}

	while (1) {
		if (visit[pointerForClock] == 1) {
			visit[pointerForClock] = 0;
		}
		else {
			mm[pointerForClock] = number;
			visit[pointerForClock] = 1;
			pointerForClock = (pointerForClock + 1) % (sizeof(mm) / sizeof(mm[0]));
			break;
		}
		pointerForClock = (pointerForClock + 1) % (sizeof(mm) / sizeof(mm[0]));
	}
	return 0;
}

4.性能测试

为了测试在不同的页面访问序列及不同的虚拟内存尺寸下,不同淘汰算法发生的页面置换情况,采用控制变量法进行处理。
部分访问序列如下:
在这里插入图片描述
对该序列测试结果:
在这里插入图片描述
可见,对一个页面访问序列,发生页面置换次数的平均值为21071

4.1 不同内存尺寸各类算法的缺页率影响
变量: 内存尺寸
恒量如下:
所有算法使用页面访问序列:70120304230321201701
在这里插入图片描述
可见,当 memory=6 时,各类算法的缺页率开始稳定,因此,我们选择 memory=6 来继续进行下面的实验。
4.2 不同访问序列长度对各类算法的缺页率的影响
变量: 访问序列长度
恒量如下:
(1)实际内存的大小=6
(2)虚拟内存的尺寸 N=20
(3)工作集中包含的页数 e=10
(4)工作集移动率 m=20
在这里插入图片描述

5.实验分析

通过实验数据可以看出,最佳替换算法的缺页率最低,且最为稳定,算法最优,但它是理想化算法,实际上却难于实现(假设后面的序列已知,但实际情况是后面序列无法预测),故主要用于算法评价参照。
先进先出置换算法简单直观,但不符合进程实际运行规律,性能较差,故实际应用少。
最久最近未使用置换算法是用序列的前部来推测后部,适用于大部分类型的程序,性能较好,现在也处于主流地位,但需要较多的硬件支持。
Clock算法需要根据页面内存是否被访问来决定是否置换该页面,性能也较好,但选择淘汰页可能要经过多次扫描。
将算法之间进行比较,最优算法比 LRU 算法要优越,原因是最优算法可以预知下次出现的访问页是哪个,而 LRU 算法只能预测最近最久未使用的那个页面是最不可能先被访问的,所以, LRU 算法有一定的误差,缺页率较高。从算法开销来说,FIFO是最容易实现的,只需有一个指向最老的物理块指针即可,时间复杂度为O(1);最佳置换需为其每个物理内存块,设置最近访问次序位,仅选出最小的最近访问次序物理块的时间复杂度为O(n),通过优化可达O(log_2⁡N);LRU需使用一个栈来淘汰栈底的物理块,而判断栈内是否有待访问的物理块时间复杂度需O(n),移出与移入栈时间复杂度为O(1);Clock算法需为每个物理块设置访问位和修改位,在寻找待淘汰物理块的时间复杂度为O(n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值