- 一、实验内容
- 二、实验原理
- 三、实验步骤
- 1.画出每个页面置换算法流程图
- OPT:
- Ofar()流程图:
- Lfar()流程图:
- FIFO:
- 2.对算法所用的数据结构进行说明:
- 3. 测试数据随机产生。不可手工输入:
- 4.多次测试程序,截屏输出实验结果:
- OPT
- LRU
- FIFO
- 5.根据实验结果与理论课讲述的原理进行实验分析
- 五、实验数据及源代码
- 总结
一、实验内容
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函数不同
Lfar()流程图:P=start(图写错了)
Far算法是变量内存数组,然后寻找距离最远的数,目的是更新或使最远页数在内存中的下标值,然后返回这个需要更改的下标值
FIFO: 2.对算法所用的数据结构进行说明:Lfar的流程,只改变了distance计算方法和p的移动方向
数组说明:
随机生成320条指令函数:
cpage():
将随机指令转换成页地址流的函数
find():
判断页是否在内存中 其实是一个查找数num是否在参数数组内的一个函数
Ofar():
在OPT算法中寻找最久未使用或未来不使用的内存内的页号的下标
Lfar():
LRU算法中寻找最近最久未使用的内存内的页号的下标
这里加入LRU算法中的查找所需下标的函数,因为两个函数很像,只是查找方向相反
LRU算法实现
OPT算法实现
和上图一样,因为这部分函数主要是判断指针所指的页号是否在内存,并调用查找需要替换的内存下标并进行替换
FIFO算法实现
LRU因为320,32,不易观察,下图数据暂时修改成150和15
只显示发生缺页中断时的页地址流和内存表
FIFO因为320,32,不易观察,下图数据暂时修改成150和15
只显示发生缺页中断时的页地址流和内存表
5.根据实验结果与理论课讲述的原理进行实验分析出现该问题的原因: 首次构造链表算法写错了,改成后插法就可以了(为了记录问题所以没有更改)
第一次输出出问题原因在于我算法是先将内存表填满,FIFO算法内存表用了链表,在第一次构建链表的时候没有用后插法创建链表,有问题的算法为:
过程为先赋值p->data,在创建新结点,p后移,但是这样的问题是当最后一个数赋值后,后面还是会连着一个data为空的新结点,导致在print的时候p指向最后一个数据时p->next不为NULL(指向空结点,空结点next为NULL)
但是不影响后面的算法,因为last指向是正确的
OPT算法页号命中率:
LRU算法页号命中率:
输出LRU命中率会出现只输出一部分从内存大小最小值开始的命中率的问题(如只输出内存4k到17k就停下来了)通过更改内存大小的区间(如设置18k-31k)才得到内存由4k-31k的命中率,所以上面的结果图是运行了两次然后截图的
( 另外两个就不会,我也不知道为什么)
FIFO算法命中率
五、实验数据及源代码写了很多输出语句用于判断算法是否正确,可以忽略
#include#include #include 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 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);//替换的数组下标 caqa[change] = page[p];//替换后p指针后移 } 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 //如果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 if (!Ffind(head, page[j])) { falsehit++; 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; } 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);//替换的数组下标 caqa[change] = page[p];//替换后p指针后移 } 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); }
总结



