操作系统 ---虚拟内存管理
作者:互联网
操作系统 ---虚拟内存管理
【实验目的】
通过模拟实现请求页式存储管理的几种基本页面置换算法,了解虚拟存储技术的特点,掌握虚拟存储请求页式存储管理中几种基本页面置换算法的基本思想和实现过程,并比较它们的效率。
【实验内容】
设计一个虚拟分页系统,并使用下述算法计算访问命中率。
1、先进先出的算法(FIFO)
2、最近最久未使用算法(LRU)
3、最不经常使用算法(LFU)
4、最近未使用算法(NUR)
5、最佳淘汰算法(OPT)
命中率=1-页面失效次数/页地址流长度
【实验准备】
1.准备:首先用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页。
2.实现算法:忽略指令的地址映射过程,首先直接生成合法的页面访问序列号,并设置关键的数据结构-扩充页表,再针对不同的算法计算出相应的命中率。
【实验步骤】
一、虚拟存储系统
Linux中,为了提高内存利用率,提供了内外存进程对换机制;内存空间的分配和回收均以页为单位进行;一个进程只需将其一部分(段或页)调入内存便可运行;还支持请求调页的存储管理方式。
当进程在运行中需要访问某部分程序和数据时,发现其所在页面不在内存,就立即提出请求(向CPU发出缺中断),由系统将其所需页面调入内存。这种页面调入方式叫请求调页。
为实现请求调页,核心配置了四种数据结构:页表、页框号、访问位、修改位、有效位、保护位等。
二、页面置换算法
当CPU接收到缺页中断信号,中断处理程序先保存现场,分析中断原因,转入缺页中断处理程序。该程序通过查找页表,得到该页所在外存的物理块号。如果此时内存未满,能容纳新页,则启动磁盘I/O将所缺之页调入内存,然后修改页表。如果内存已满,则须按某种置换算法从内存中选出一页准备换出,是否重新写盘由页表的修改位决定,然后将缺页调入,修改页表。利用修改后的页表,去形成所要访问数据的物理地址,再去访问内存数据。整个页面的调入过程对用户是透明的。
实现页面置换算法:
1.进先出的算法(FIFO)(Fisrt In First Out)
2.最近最少使用的算法(LRU)(Least Recently Used)
3.最佳淘汰算法(OPT)(Optimal)
4.最少访问页面算法(LFU)(Least Frequently Used)
5.最近最不经常使用算法(NUR)(No Used Recently)
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define TRUE 1
#define FALSE 0
#define INVALID -1
//#define NULL 0
#define total_instruction 320 /*指令流长*/
#define total_vp 32 /*虚页长*/
#define clear_period 50 /*清0周期*/
typedef struct /*页面结构*/
{
int pn; /* 页号 logic number */
int pfn; /* 页面框架号 physical frame number(物理块号) */
int counter; /* 计数器 */
int time; /* 时间 */
} pl_type;
pl_type pl[total_vp]; /*页面线性结构---指令序列需要使用地址*/
typedef struct pfc_struct /*页面控制结构,调度算法的控制结构*/
{
int pn;
int pfn;
struct pfc_struct *next;
} pfc_type;
pfc_type pfc[total_vp], *freepf_head, *busypf_head, *busypf_tail;
int diseffect, a[total_instruction]; /* a[]为指令序列*/
int page[total_instruction], offset[total_instruction]; /*地址信息*/
int initialize( int );
int FIFO( int );
int LRU( int );
int LFU( int );
int NUR( int ); /* not use recently */
int OPT( int );
int main()
{
int s, i, j;
srand( 10 * getpid() ); /*由于每次运行时进程号不同,故可用来作为初始化随机数队列的“种子”*/
s=(float)319*rand()/32767/32767/2+1; /*正态分布*/
for ( i = 0; i < total_instruction; i += 4 ) /*产生指令队列*/
{
//printf("\ns=== %d\n", s);
if ( s < 0 || s > 319 )
{
printf( "Wheni==%d,Error,s==%d\n", i, s );
exit( 0 );
}
a[i] = s; /*任选一指令访问点m*/
a[i + 1] = a[i] + 1; /*顺序执行一条指令*/
a[i + 2] = (float) a[i] * rand() / 32767 /32767/2; /*执行前地址指令m*/
a[i + 3] = a[i + 2] + 1; /*顺序执行一条指令*/
s=(float)(318-a[i+2])*rand()/32767/32767/2+a[i+2]+2;
if ( (a[i + 2] > 318) || (s > 319) )
printf( "a[%d+2],a number which is:%d and s==%d\n", i, a[i + 2], s );
}
for ( i = 0; i < total_instruction; i++ ) /*将指令序列变换成页地址流*/
{
printf( "a[%d]=%d, ", i, a[i] );
page[i] = a[i] / 10;
offset[i] = a[i] % 10;
}
for ( i = 4; i <= 32; i++ ) /*用户内存工作区从4个页面到32个页面*/
{
printf( "---%2d pageframes---\n", i );
FIFO( i );
LRU( i );
LFU( i );
NUR( i );
OPT( i );
}
return(0);
}
/*初始化相关数据结构total_pf表示内存的块数 */
int initialize( int total_pf )
{
int i;
diseffect = 0;
for ( i = 0; i < total_vp; i++ )
{
pl[i].pfn = INVALID; /*置页面控制结构中的页号,页面为空*/
pl[i].counter = 0; /*页面控制结构中的访问次数为0*/
pl[i].time = -1; /*访问的时间*/
}
for ( i = 0; i < total_pf - 1; i++ ) /*建立pfc[i-1]和pfc[i]之间的链接*/
{
pfc[i].next = &pfc[i + 1];
pfc[i].pfn = i;
}
pfc[total_pf - 1].next = NULL;
pfc[total_pf - 1].pfn = total_pf - 1;
freepf_head = &pfc[0]; /*空页面队列的头指针为pfc[0]*/
return(0);
}
int FIFO( int total_pf ) /*先进先出算法total_pf用户进程的内存页面数*/
{
int i, j;
pfc_type *p; /*中间变量*/
initialize( total_pf ); /*初始化相关页面控制用数据结构*/
busypf_head = busypf_tail = NULL; /*忙页面队列头,队列尾链接*/
for ( i = 0; i < total_instruction; i++ )
{
if ( pl[page[i]].pfn == INVALID ) /*页面失效,即缺页*/
{
diseffect += 1; /*失效(缺页)次数*/
if ( freepf_head == NULL ) /*无空闲页面*/
{
p = busypf_head->next;
pl[busypf_head->pn].pfn = INVALID;
freepf_head = busypf_head; /*释放忙页面队列的第一个页面*/
freepf_head->next = NULL; /*表明还是缺页*/
busypf_head = p;
}
p = freepf_head->next;
freepf_head->pn = page[i];
pl[page[i]].pfn = freepf_head->pfn;
freepf_head->next = NULL; /*使busy的尾为null*/
if ( busypf_tail == NULL )
{
busypf_tail = busypf_head = freepf_head;
}else {
busypf_tail->next = freepf_head;
busypf_tail = freepf_head;
}
freepf_head = p;
}
}
printf( "FIFO:%6.4f\n", 1 - (float) diseffect / 320 );
return(0);
}
int LRU( int total_pf ) /*最近最久未使用算法leastrecently used*/
{
int min,minj,i,j,present_time;
initialize(total_pf);
present_time=0;
for(i=0;i<total_instruction;i++)
{
if(pl[page[i]].pfn==INVALID) /*页面失效*/
{
diseffect++;
if(freepf_head==NULL) /*无空闲页面*/
{
min=32767;
for(j=0;j<total_vp;j++) /*找出time的最小值*/
if(min>pl[j].time&&pl[j].pfn!=INVALID)
{
min=pl[j].time;
minj=j;
}
freepf_head=&pfc[pl[minj].pfn]; //腾出一个单元
pl[minj].pfn=INVALID;
pl[minj].time=-1;
freepf_head->next=NULL;
}
pl[page[i]].pfn=freepf_head->pfn; //有空闲页面,改为有效
pl[page[i]].time=present_time;
freepf_head=freepf_head->next; //减少一个free 页面
}
else
pl[page[i]].time=present_time; //命中则增加该单元的访问次数
present_time++;
}
printf("LRU:%6.4f\n",1-(float)diseffect/320);
return(0);
}
int NUR( int total_pf ) /*最近未使用算法Not Usedrecently count表示*/
{
int i, j, dp, cont_flag, old_dp;
pfc_type *t;
initialize( total_pf );
dp = 0;
for ( i = 0; i < total_instruction; i++ )
{
if ( pl[page[i]].pfn == INVALID ) /*页面失效(缺页)*/
{
diseffect++;
if ( freepf_head == NULL ) /*无空闲页面*/
{
cont_flag = TRUE;
old_dp = dp;
while ( cont_flag )
{
if ( pl[dp].counter == 0 && pl[dp].pfn != INVALID )
cont_flag = FALSE;
else{
dp++;
if ( dp == total_vp )
dp = 0;
if ( dp == old_dp )
for ( j = 0; j < total_vp; j++ )
pl[j].counter = 0;
}
}
freepf_head = &pfc[pl[dp].pfn];
pl[dp].pfn = INVALID;
freepf_head->next = NULL;
}
pl[page[i]].pfn = freepf_head->pfn;
freepf_head->pn = page[i];
freepf_head = freepf_head->next;
}else
pl[page[i]].counter = 1;
if ( i % clear_period == 0 )
for ( j = 0; j < total_vp; j++ )
pl[j].counter = 0;
}
printf( "NUR:%6.4f\n", 1 - (float) diseffect / 320 );
return(0);
}
int OPT( int total_pf ) /*最佳置换算法*/
{
int i,j, max,maxpage,d,dist[total_vp];
pfc_type *t;
initialize(total_pf);
for(i=0;i<total_instruction;i++)
{ //printf("In OPT for 1,i=%d\n",i); //i=86;i=176;206;250;220,221;192,193,194;258;274,275,276,277,278;
if(pl[page[i]].pfn==INVALID) /*页面失效*/
{
diseffect++;
if(freepf_head==NULL) /*无空闲页面*/
{
for(j=0;j<total_vp;j++)
if(pl[j].pfn!=INVALID) dist[j]=32767; /* 最大"距离" */
else dist[j]=0;
d=1;
for(j=i+1;j<total_instruction;j++)
{
if(pl[page[j]].pfn!=INVALID)
dist[page[j]]=d;
d++;
}
max=-1;
for(j=0;j<total_vp;j++)
if(max<dist[j])
{
max=dist[j];
maxpage=j;
}
freepf_head=&pfc[pl[maxpage].pfn];
freepf_head->next=NULL;
pl[maxpage].pfn=INVALID;
}
pl[page[i]].pfn=freepf_head->pfn;
freepf_head=freepf_head->next;
}
}
printf("OPT:%6.4f\n",1-(float)diseffect/320);
return(0);
}
/*该算法时根据已知的预测未知的,leastfrequency Used是最不经常使用置换法*/
int LFU( int total_pf )
{
int i, j, min, minpage;
pfc_type *t;
initialize( total_pf );
for ( i = 0; i < total_instruction; i++ )
{
if ( pl[page[i]].pfn == INVALID ) /*页面失效*/
{
diseffect++;
if ( freepf_head == NULL ) /*无空闲页面*/
{
min = 32767;
/*获取counter的使用用频率最小的内存*/
for ( j = 0; j < total_vp; j++ )
{
if ( min > pl[j].counter && pl[j].pfn != INVALID )
{
min = pl[j].counter;
minpage = j;
}
}
freepf_head = &pfc[pl[minpage].pfn];
pl[minpage].pfn = INVALID;
pl[minpage].counter = 0;
freepf_head->next = NULL;
}
pl[page[i]].pfn = freepf_head->pfn; /*有空闲页面,改为有效 */
pl[page[i]].counter++;
freepf_head = freepf_head->next; /* 减少一个free 页面 */
}else {
pl[page[i]].counter;
pl[page[i]].counter = pl[page[i]].counter + 1;
}
}
printf( "LFU:%6.4f\n", 1 - (float) diseffect / 320 );
return(0);
}
标签:head,操作系统,int,freepf,pfn,---,虚拟内存,total,pl 来源: https://blog.csdn.net/qq_40833874/article/details/117366683