欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-14 21:41:52
...

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 算法流程图
16281053_杨瑷彤_操作系统第四次实验
代码:

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 算法流程图

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

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 算法流程图
16281053_杨瑷彤_操作系统第四次实验
代码:

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 算法流程图
16281053_杨瑷彤_操作系统第四次实验代码:

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.性能测试

为了测试在不同的页面访问序列及不同的虚拟内存尺寸下,不同淘汰算法发生的页面置换情况,采用控制变量法进行处理。
部分访问序列如下:
16281053_杨瑷彤_操作系统第四次实验
对该序列测试结果:
16281053_杨瑷彤_操作系统第四次实验
可见,对一个页面访问序列,发生页面置换次数的平均值为21071

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

5.实验分析

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