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

操作系统第四次作业--页面置换算法

程序员文章站 2022-03-23 08:33:42
...

实验目的

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

实验环境

  • 操作系统:WINDOWS
  • 软件:Visual Studio

实验背景

  • 请求分页虚拟内存管理
    请求分页虚拟内存管理是建立在基本分页基础上的,为了能支持虚拟存储器功能,而增加了请求调页功能和置换功能。
  • 工作集
    多数程序都显示出高度的局部性,也就是说,在一个时间段内,一组页面被反复引用。这组被反复引用的页面随着时间的推移,其成员也会发生变化。有时这种变化是剧烈的,有时这种变化则是渐进的。我们把这组页面的集合称为工作集。
  • 缺页率
    缺页中断次数/总的页面访问次数

实验要求

  • 页表用整数数组或结构数组来表示

  • 页面访问序列串是一个整数序列,整数的取值范围为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步,否则结束

实验过程

算法介绍

(1)最佳置换算法
最佳置换算法的主要思想是,在发生页面替换时,被替换的对象应该满足,在以后的页面访问中,该对象不会再次被访问或者较晚被访问。是一种理想化算法,具有最好性能(对于固定分配页面方式,本法可保证获得最低的缺页率),但实际上却难于实现,故主要用于算法评价参照
(2)先进先出置换算法
总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。实现方法为:把一个进程已调入内存的页面按先后次序链接成一个队列,并设置一个指针(称为替换指针),始终指向最老的页面。
(3)最近最久未使用置换算法
最近最久未使用置换算法的主要思想是,在发生页面替换时,被替换的页面应该满足,在之前的访问队列中,该对象截止目前未被访问的时间最长
(4)改进型Clock置换算法
改进型Clock置换算法的主要思想是,在每次页面替换时,总是尽可能地先替换掉既未被访问又未被修改的页面。
(5)页面缓冲算法
设立空闲页面链表和已修改页面链表采用可变分配和基于先进先出的局部置换策略,并规定被淘汰页先不做物理移动,而是依据是否修改分别挂到空闲页面链表或已修改页面链表的末尾,空闲页面链表同时用于物理块分配,当已修改页面链表达到一定长度如Z个页面时,一起将所有已修改页面写回磁盘,故可显著减少磁盘I/O操作次数

数据结构设计

  • 数组:
    定义的时候利用指针定义,然后根据全局变量block设定的给进程分配的物理内存的块数动态分配内存。一旦完成内存分配,不再改变数组的大小。
    用到数组结构来实现的算法程序有:最佳置换算法,先进先出置换算法,最近最久未使用置换算法,改进型置换算法。
  • 队列:
    为单向队列,队列长度仍然由全局变量指定。
    用到队列的算法程序有:先进先出置换算法。队列结点元素的结构体如下
typedef struct node
{
	int num;
	node* next;
} Node, *pNode;

typedef struct queue
{
	int n;
	pNode front;
	pNode rear;

} Queue, *pQueue;

  • 链表:
    主要是将装入内存的页块串联起来。
    用到链表的算法程序:页面缓冲算法。链表结点元素的结构体如下
struct LNode
{
    int data;//页号
    int flag;//访问位
    int modify;//修改位
    LNode* next;
};
struct Link
{
    int num;//当前链表上的结点数
    LNode* next;
};

函数说明

/****************全局共享函数****************/
void initMemo();//初始化存储空间,主要是设置分配空间的大小
void generate();//生成访问序列
bool  isInMemo (int n); //指定页号是否已经在内存中

/****************最佳置换算法****************/
void optimal (int n); //访问一个页面,执行一次最佳置换算法
void testOptimal();//算法实现函数

/****************先进先出置换算法****************/
void initQueue (pQueue q);//初始化队列
void push (pQueue q, int num);//队列中加入新的页面结点
void pop (pQueue q);//将页面移出内存
void destroy (pQueue q);//销毁队列
bool findInQueue (pQueue q, int num);//查找页面是否已经调入内存
void generate();//生成访问序列
void fifoTest();//每访问一个页面,执行一次算法
void fifo (pQueue q, int num);//先进先出置换算法实现函数

/****************最近最久未使用置换算法****************/
void LRU (int n);//每访问一个新的页面,执行一次LRU算法
void testLRU();//LRU算法实现函数

/****************改进型clock置换算法****************/
void updated_Clock (int n);//改进型clock算法实现函数
void test_Clock();//每访问一个新的页面,执行一次算法

/****************页面缓冲算法****************/
bool  isInNodes (int n); //页面是否已经在链表中
void addToLink (int data, int type);//页面添加到已修改页面链表和空闲链表上
void emptyIdle();//将空闲链表上的所有页面送出内存
void emptyModi();//将已修改页面链表上所有的链表送出内存
void PBA (int n);//PBA算法实现函数

代码实现

generate函数生成随机访问序列

void generate()
{
	srand((unsigned)time(NULL)); //用时间做种,每次产生随机数不一样
	int p = rand() % 64;
	int m = 8, e = 8;
	int i, j;
	double t;
	t = rand() % 10 / 10.0;

	for (i = 0; i < 4; i++)
	{
		for (j = i * m; j < (i + 1) *m; j++)
		{
			access[j] = (p + rand() % e) % 64;
		}

		double r = (rand() % 10) / 10.0;

		if (r < t)
		{
			p = rand() % 64;
		}

		else
		{
			p = (p + 1) % 64;
		}
	}
}

最佳置换算法

void testOptimal()
{
	initMemo();
	int i = 0;
	printf("最佳置换算法:\n");

	for (; i < 32; i++)
	{
		optimal(i);
		printf("%d %d %d\n", memo[0], memo[1], memo[2]);
	}

	printf("最佳置换算法缺页率: %2f %d\n", lost / 32.0, lost);
	lost = 0;
	free(memo);
	index = 0;
}

先进先出算法

void fifoTest()
{
	Queue q;
	pNode p;
	initQueue(&q);
	int i = 0;
	printf("先进先出置换算法\n");

	for (; i < 32; i++)
	{
		fifo(&q, access[i]);
		p = q.front->next;

		while (p)
		{
			printf("%d ", p->num);
			p = p->next;
		}

		printf("\n");
	}

	printf("先进先出算法缺页率:%f  %d\n", lost / 32.0, lost);
	destroy(&q);
}

最近最久未使用算法

void testLRU()
{
	int i;
	initMemo();
	printf("最近最久未使用算法\n");

	for (i = 0; i < 32; i++)
	{
		LRU(i);
		printf("%d %d %d\n", memo[0], memo[1], memo[2]);
	}

	printf("最近最久未使用缺页率: %2f %d \n", lost / 32.0, lost);
	lost = 0;
	index = 0;
	free(memo);
}

改进型clock置换算法

void test_Clock()
{
	int i = 0, j = 0;
	printf("改进型Clock置换算法\n");
	nodes = (LNode*)malloc(block * sizeof(LNode));

	for (i = 0; i < block; i++)
	{
		nodes[i].data = -1;
		nodes[i].flag = -1;
		nodes[i].modify = -1;
	}

	for (i = 0; i < 32; i++)
	{
		updated_Clock(i);

		for (j = 0; j < block; j++)
		{
			printf("%d ", nodes[j].data);
		}

		printf("\n");
	}

	printf("改进型Clock置换算法缺页率: %2f %d \n", lost / 32.0, lost);
	lost = 0;
	index = 0;
}

页面置换算法(PBA)

void PBA(int n)
{
	if (isInNodes(n))
	{
		printf("已装入内存\n");
	}

	else
		if (index == size)
		{
			LNode *p;

			if ((p = isinLinks(n)) != NULL)
			{
				nodes = (LNode*)realloc(nodes, (size + 1) * sizeof(LNode));
				nodes[size].data = p->data;
				nodes[size].flag = p->flag;
				nodes[size].modify = p->modify;
				nodes[size].next = p->next;
				free(p);
				size++;
				index++;
			}

			else
			{
				lost++;//缺页

				if (nodes[n % 3].modify == 1)
				{
					addToLink(nodes[n % 3].data, 1);
				}

				else
				{
					addToLink(nodes[n % 3].data, 0);
				}

				nodes[n % 3].data = access[n];
				nodes[n % 3].flag = 1;
				nodes[n % 3].next = NULL;

				if (rand() % 10 < 4)
				{
					nodes[n % 3].modify = 0;
				}

				else
				{
					nodes[n % 3].modify = 1;
				}
			}
		}

		else
		{
			nodes[index].data = access[n];
			nodes[index].flag = 1;
			nodes[index].next = NULL;

			if (rand() % 10 < 4)
			{
				nodes[index].modify = 1;
			}

			else
			{
				nodes[index].modify = 0;
			}

			index++;
		}
}

运行结果

generate函数产生的访问序列如下
操作系统第四次作业--页面置换算法
最佳置换算法
操作系统第四次作业--页面置换算法
12个页面发生了缺页,缺页率为0.375

先进先出算法
操作系统第四次作业--页面置换算法
16个页面发生缺页,缺页率为0.5000

最近最久未使用算法
操作系统第四次作业--页面置换算法
33个页面发生缺页,缺页率为1.031250

改进型Clock置换算法
操作系统第四次作业--页面置换算法
18个页面发生缺页,缺页率为0.562500

页面缓冲置换算法
操作系统第四次作业--页面置换算法
12个页面发生缺页,缺页率为0.375000

测试不同的页面访问序列

测试序列1

操作系统第四次作业--页面置换算法

算法名称 最佳置换算法 先进先出算法 最近最久未使用算法 改进型Clock置换算法 页面缓冲置换算法(PBA)
缺页数 12 16 33 18 12
缺页率 0.375 0.5 1.03125 0.5625 0.375

测试序列2

操作系统第四次作业--页面置换算法

算法名称 最佳置换算法 先进先出算法 最近最久未使用算法 改进型Clock置换算法 页面缓冲置换算法(PBA)
缺页数 13 20 39 20 13
缺页率 0.406250 0.625 1.218750 0.625 0.406250

测试不同的虚拟内存尺寸

上述测试 分配给每种算法内存空间块数为3,改变分配空间块数为5

测试序列3

操作系统第四次作业--页面置换算法

算法名称 最佳置换算法 先进先出算法 最近最久未使用算法 改进型Clock置换算法 页面缓冲置换算法(PBA)
缺页数 11 19 30 13 15
缺页率 0.343750 0.593750 0.9375 0.406250 0.468750

测试序列4

操作系统第四次作业--页面置换算法

算法名称 最佳置换算法 先进先出算法 最近最久未使用算法 改进型Clock置换算法 页面缓冲置换算法(PBA)
缺页数 6 13 20 8 9
缺页率 0.1875 0.406250 0.625 0.25 0.28125

实验总结

  • 同一种算法对不同的访问序列,其缺页率是不同。
  • 最佳置换算法的缺页率是最低的,剩下的几种算法中,页面缓冲算法的缺页率要低于其他置换算法。改进型clock算法稍微好于先进先出算法和最近最久未使用算法。先进先出算法优于最近最久未使用算法。
  • 对比内存块数为3和内存块数为5两种情况下的同一序列下的同一,可以发现,算法的缺页率还跟分配的内存块数有关系,分配的内存块数越多,缺页率越低。导入内存的块数越多,发生缺页的可能性就越小。

源码

https://github.com/notdz56/16281023-/tree/master/操作系统第四次实验代码