实验报告书.docx

上传人:b****2 文档编号:2791030 上传时间:2023-05-04 格式:DOCX 页数:15 大小:111.52KB
下载 相关 举报
实验报告书.docx_第1页
第1页 / 共15页
实验报告书.docx_第2页
第2页 / 共15页
实验报告书.docx_第3页
第3页 / 共15页
实验报告书.docx_第4页
第4页 / 共15页
实验报告书.docx_第5页
第5页 / 共15页
实验报告书.docx_第6页
第6页 / 共15页
实验报告书.docx_第7页
第7页 / 共15页
实验报告书.docx_第8页
第8页 / 共15页
实验报告书.docx_第9页
第9页 / 共15页
实验报告书.docx_第10页
第10页 / 共15页
实验报告书.docx_第11页
第11页 / 共15页
实验报告书.docx_第12页
第12页 / 共15页
实验报告书.docx_第13页
第13页 / 共15页
实验报告书.docx_第14页
第14页 / 共15页
实验报告书.docx_第15页
第15页 / 共15页
亲,该文档总共15页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

实验报告书.docx

《实验报告书.docx》由会员分享,可在线阅读,更多相关《实验报告书.docx(15页珍藏版)》请在冰点文库上搜索。

实验报告书.docx

实验报告书

 

实验报告书

 

学生姓名张伟

学号11101020228

班级计11-2

 

2013—2014学年第一学期

 

《计算机操作系统》实验报告

实验名称

存储管理实验

实验序号

2

实验日期

2013.11-2013.12

实验人

张伟

一、实验目的和要求

1.实验目的

请求页式存储管理是一种常用的虚拟存储管理技术。

本实验目的是通过请求页式存储管理中页面置换算法的模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。

2.实验要求及考核

(1)实验课与正常上课一样,要求按时出勤。

(2)实验须独立完成,可以查阅各种资料。

(3)实验完毕要求提交纸质实验报告,报告格式参照所提供的模板。

(4)本次实验的验机时间为13周周三,实验报告应在13周周三统一提交。

(5)实验成绩由平时出勤、验机情况和实验报告三部分构成。

二、相关背景知识

1.请求页式管理

Linux系统中,为了提高内存利用率,提供了内外存进程对换机制;内存空间的分配和回收均以页为单位进行;一个进程只需将其一部分(段或页)调入内存便可运行;还支持请求调页的存储管理方式。

当进程在运行中需要访问某部分程序和数据时,发现其所在页面不在内存,就立即提出请求(向CPU发出缺中断),由系统将其所需页面调入内存。

这种页面调入方式叫请求调页。

为实现请求调页,核心配置了四种数据结构:

页表、页帧(框)号、访问位、修改位、有效位、保护位等。

页表:

 

表2-1页表

流程图:

图2-1流程图

中断位和外存始址用于标识出所缺页在外存的地址,改变位标识该页在内存时是否被修改过。

2.请求页式管理中的置换算法(主要介绍本次试验中的两种)

(1)先进先出页面淘汰算法(FIFO)

FIFO算法认为先调入内存的页不再被访问的可能性要比其它页大,因而选择最先调入内存的页换出。

实现FIFO算法需要把各个已分配页面按分配时间顺序链接起来,组成FIFO队列,并设置一置换指针指向FIFO队列的队首页面。

这样,当要进行置换时,只需把置换指针所指的FIFO队列前头的页顺次换出,而把换入的页链接在FIFO队尾即可。

Belady现象:

一般来说,对于任一作业或进程,如果给它分配的内存页面数越接近于它所要求的页面数,则发生缺页的次数会越少。

在极限情况下,这个推论是成立的。

因为如果给一个进程分配了它所要求的全部页面,则不会发生缺页现象。

但是,使用FIFO算法时,在未给进程或作业分配足它所要求的页面数时,有时会出现分配的页面数增多,缺页次数反而增加的奇怪现象。

这种现象称为Belady现象。

(2)最近最久未使用页面淘汰法(LRU)

选择内存中最久未使用的页面被置换。

这是局部性原理的合理近似,性能接近最佳算法。

但由于需要记录页面使用时间的先后关系,硬件开销太大。

硬件机构如:

A.一个特殊的栈:

把被访问的页面移到栈顶,于是栈底的是最久未使用页面。

B.每个页面设立移位寄存器:

被访问时左边最高位置1,定期右移并且最高位补0,于是寄存器数值最小的是最久未使用页面。

3.随机数产生办法

关于随机数产生办法,Linux或UNIX系统提供函数srand()和rand(),分别进行初始化和产生随机数。

例如:

srand();

语句可初始化一个随机数;

a[0]=10*rand()/65535*319+1;

a[1]=10*rand()/65535*a[0];

语句可用来产生a[0]与a[1]中的随机数。

三、实验内容

1.通过随机数产生一个指令序列,共320条指令。

指令的地址按下述原则生成:

(1)50%的指令是顺序执行的;

(2)25%的指令是均匀分布在前地址部分;

(3)25%的指令是均匀分布在后地址部分;

具体的实施方法是:

(1)在[0,319]的指令地址之间随机选取一起点m;

(2)顺序执行一条指令,即执行地址为m+1的指令;

(3)在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’;

(4)顺序执行一条指令,其地址为m’+1;

(5)在后地址[m’+2,319]中随机选取一条指令并执行;

(6)重复上述步骤1~5,直到执行320次指令。

2.将指令序列变换成页地址流,设

(1)页面大小为1K;

(2)用户内存容量为4页到32页;

(3)用户虚存容量为32K。

在用户虚存中,按每K存放10条指令排列虚存地址,即320条指令在虚存中存放的方式为:

第0条至第9条指令为第0页(对应虚存地址为[0,9]);

第10条至第19条指令为第1页(对应虚存地址为[10,19]);

……

第310条至第319条指令为第31页(对应虚存地址为[310,319]);

按以上方式,用户指令可以组成32页。

3.计算并输出下述各种算法在不同内存容量下的命中率。

(1)先进先出页面淘汰算法(FIFO)

(2)最近最久未使用页面淘汰法(LRU)

命中率=1-页面失效次数/页地址流长度

在本实验中,页地址流长度为320,页面失效次数为每次访问相应指令时,该指令对应的页不在内存的次数。

四、关键数据结构与函数的说明

1.srand()与rand()

函数rand()是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。

如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。

而使用同种子相同的数调用srand()会导致相同的随机数序列被生成。

srand((unsigned)time(NULL))则使用系统定时/计数器的值做为随机种子。

每个种子对应一组根据算法预先生成的随机数,所以,在相同的平台环境下,不同时间产生的随机数会是不同的,相应的,若将srand(unsigned)time(NULL)改为srand(TP)(TP为任一常量),则无论何时运行、运行多少次得到的“随机数”都会是一组固定的序列,因此srand生成的随机数是伪随机数。

库函数中系统提供了两个函数用于产生随机数:

srand()和rand()。

原型为:

函数一:

intrand(void);

从srand(seed)中指定的seed开始,返回一个[seed,RAND_MAX(0x7fff)]间的随机整数。

函数二:

voidsrand(unsignedseed);

参数seed是rand()的种子,用来初始化rand()的起始值。

但是,要注意的是所谓的“伪随机数”指的并不是假的随机数。

其实绝对的随机数只是一种理想状态的随机数,计算机只能生成相对的随机数即伪随机数。

计算机生成的伪随机数既是随机的又是有规律的:

一部份遵守一定的规律,一部份则不遵守任何规律。

比如“世上没有两片形状完全相同的树叶”,这体现到了事物的特性:

差异性;但是每种树的叶子都有近似的形状,这正是事物的共性:

规律性。

从这个角度讲,我们就可以接受这样的事实了:

计算机只能产生伪随机数而不是绝对的随机数。

系统在调用rand()之前都会自动调用srand(),如果用户在rand()之前曾调用过srand()给参数seed指定了一个值,那么rand()就会将seed的值作为产生伪随机数的初始值;而如果用户在rand()前没有调用过srand(),那么系统默认将1作为伪随机数的初始值。

如果给了一个定值,那么每次rand()产生的随机数序列都是一样的。

所以为了避免上述情况的发生我们通常用srand((unsigned)time(0))或者srand((unsigned)time(NULL))来产生种子。

如果仍然觉得时间间隔太小,可以在(unsigned)time(0)或者(unsigned)time(NULL)后面乘上某个合适的整数。

例如,srand((unsigned)time(NULL)*10)

另外,关于time_ttime(0):

time_t被定义为长整型,它返回从1970年1月1日零时零分零秒到目前为止所经过的时间,单位为秒。

2.定义结构体

typedefstruct//页面结构

{

intpn,//页面序号

pfn,//页面所在内存区的帧号

time;//上次访问的时间

}pl_type;

structpfc_struct

{//页面控制结构

intpn,//页面号

pfn;//内存区页面的帧号

structpfc_struct*next;//页面指针,用于维护内存缓冲区的链式结构

};

typedefstructpfc_structpfc_type;//主存区页面控制结构别名

3.定义常量、变量

#definetotals320//指令流长

#definetotal_page32//虚页长

pl_typepl[total_page];//页面结构数组

pfc_typepfc[total_page],//主存区页面控制结构数组

*free_head;//主存区页面控制结构的空闲页面头指针

intdiseffect;//页错误计数器,初次把页面载入主存时也当做页错误

inta[totals];//随即指令流数组

intpage[totals];//指令对应的页面号

intoffset[totals];//指令所在页面中的偏移量

4.功能函数声明

intinitialize(int);//初始化页面结构数组和页面控制结构数组

intFIFO(int);//先进先出算法

intLRU(int);//最近最久未使用算法

五、编译与执行过程截图

执行后出现了随机指令序列,总共320条指令,如图5-1所示。

图5-1

然后调用FIFO函数与LRU函数计算命中率,显示其结果,如图5-2所示。

图5-2

六、实验结果与分析

结果:

由执行现象可得知,增加作业的内存块数,可以降低缺页率,对于不同的算法,增加物理块数都能降低缺页率,只是效果有所不同。

理论上,LRU具有比FIFO更好的性能,可是实验中在内存块数量相对少时,现象反应FIFO的性能比LRU好,当内存块数量越来越多时,LRU性能明显比FIFO更好。

分析:

指令流的产生方式要能体现局部性原理,本实验中指令流设计方式能否最佳地体现局部性原理,还有待验证,并且指令的数量相对较少。

一般情况下,LRU具有比FIFO更好的性能。

FIFO置换算法设计简单,容易理解。

但它的效率并不是总能达到令人满意的效果。

这种算法只有在顺序访问地址空间时才能达到理想效果,但根据程序的局部性原理,那些常被访问的页面,往往要在主存中停留得最久,FIFO算法却将会将其换出页面,留下的只是一些新调入的指令,这将导致内存频繁换页。

而LRU则选择在最近一段时间里最久没有使用过的页面予以置换,LRU算法是与每个页面最后使用的时间有关的。

当必须置换一个页面时,LRU算法选择过去一段时间里最久未被使用的页面。

这种算法以“最近的过去”作为“最近的将来”的近似,较好地利用了程序的局部性原理。

一般情况下,能取得较好的效果,是经常采用的页面置换算法。

七、调试时遇到的问题及解决方法(提供BUG截屏)

1.指针赋值时出错。

解决办法:

程序中定义的指针变量子在赋值时取得是地址,故需要加上取地址符“&”。

2.结果未达到预定效果,不正确,如图7-1,32page时命中率>0.9。

图7-1

解决办法:

在LRU算法中,CurrentTime应该自增,可是在代码中并没有,加上CurrentTime++,而且在FIFO算法中,指针的调用出现了问题,修改赋值即可。

八、调试后的程序源代码

#include

#include

#include//在window操作系统下要屏蔽此条指令

#include

#ifndef_UNISTD_H

#define_UNISTD_H

#include

#include

#endif

#definetotals320//指令流长

#definetotal_page32//虚页长

typedefstruct//页面结构

{

intpn,//页面序号

pfn,//页面所在内存区的帧号

time;//上次访问的时间

}pl_type;

pl_typepl[total_page];//页面结构数组

structpfc_struct{//页面控制结构

intpn,//页面号

pfn;//内存区页面的帧号

structpfc_struct*next;//页面指针,用于维护内存缓冲区的链式结构

};

typedefstructpfc_structpfc_type;//主存区页面控制结构别名

pfc_typepfc[total_page],//主存区页面控制结构数组

*free_head;//主存区页面控制结构的空闲页面头指针

intdiseffect;//页错误计数器,初次把页面载入主存时也当做页错误

inta[totals];//随即指令流数组

intpage[totals];//指令对应的页面号

intoffset[totals];//指令所在页面中的偏移量

intinitialize(int);//初始化页面结构数组和页面控制结构数组

intFIFO(int);//先进先出算法

intLRU(int);//最近最久未使用算法

intmain()

{

ints;//随机数

inti;

srand(10*getpid());//每次运行时进程号不同,用来作为初始化随机数队列的"种子"

s=(int)((float)(totals-1)*(rand()/(RAND_MAX+1.0)));

printf("\n----------------Randing---------------\n");

for(i=0;i

{

a[i]=s;//任选一指令访问点m

a[i+1]=a[i]+1;//顺序执行一条指令

a[i+2]=(int)((float)a[i]*(rand()/(RAND_MAX+1.0)));//执行前地址指令m'

a[i+3]=a[i+2]+1;//顺序执行一条指令

printf("%6d%6d%6d%6d\n",a[i],a[i+1],a[i+2],a[i+3]);

s=(int)((float)((totals-1)-a[i+2])*(rand()/(RAND_MAX+1.0)))+a[i+2];

}

printf("--------------------------------------\n");

for(i=0;i

{

page[i]=a[i]/10;

offset[i]=a[i]%10;

}

printf("\n---------------DisplayingHit-----------\n");

printf("Page\tFIFO\tLRU\n");

for(i=4;i<=32;i++)//用户内存工作区从个页面到个页面

{

printf("%2d\t",i);

FIFO(i);

LRU(i);

printf("\n");

}

return0;

}

//初始化页面结构数组和页面控制结构数组

intinitialize(inttotal_pf)

{

inti;

diseffect=0;

for(i=0;i

{

pl[i].pn=i;

pl[i].pfn=-1;//置页面所在主存区的帧号为-1.表示该页不在主存中

pl[i].time=-1;//置页面结构中的上次访问的时间为-1

}

for(i=0;i

{

pfc[i].next=&pfc[i+1];//建立pfc[i-1]和pfc[i]之间的链接

pfc[i].pfn=i;//初始化主存区页面的帧号

}

pfc[total_pf-1].next=NULL;

pfc[total_pf-1].pfn=total_pf-1;

free_head=&pfc[0];//主存区页面控制结构的空闲页面头指针指向pfc[0]

return0;

}

//先进先出算法版本

intFIFO(inttotal_pf)

{

inti;

intuse[total_page];

intswap=0;

initialize(total_pf);

pfc_type*pnext,*head;

pnext=free_head;

head=free_head;

for(i=0;i

diseffect=0;

for(i=0;i

{

if(pl[page[i]].pfn==-1)//页面失效,不在主存中

{

diseffect++;

if(free_head==NULL)//无空闲页面

{

while(use[pnext->pfn]==1)

{

use[pnext->pfn]=0;

pnext=pnext->next;

if(pnext==NULL)pnext=head;

}

//换出被替换的页

pl[pnext->pn].pfn=-1;

swap=1;

}

if(use[pnext->pfn]==0)//如果使用位为0,则换入相应的页

{

pl[page[i]].pfn=pnext->pfn;//页面结构中要标记帧号

pnext->pn=page[i];//页面控制结构中要标记页号

use[pnext->pfn]=1;//重置使用位为

pnext=pnext->next;

if(pnext==NULL)pnext=head;

if(swap==0){free_head=free_head->next;}

}

}

}

printf("%6.3f\t",1-(float)diseffect/320);

return0;

}

//最近最久未使用算法

intLRU(inttotal_pf)

{

intMinT;//最小的访问时间,即很久没被访问过

intMinPn;//拥有最小的访问时间的页的页号

inti,j;

intCurrentTime;//系统当前时间

initialize(total_pf);//初始化页面结构数组和页面控制结构数组

CurrentTime=0;

diseffect=0;

for(i=0;i

{

if(pl[page[i]].pfn==-1)//页面失效

{

diseffect++;//页错误次数加

if(free_head==NULL)//无空闲页面

{

MinT=100000;

for(j=0;j

{//找出time的最小值,表明该页很久没被访问过

if(MinT>pl[j].time&&pl[j].pfn!

=-1)

{

MinT=pl[j].time;

MinPn=j;

}

}

free_head=&pfc[pl[MinPn].pfn];//最久没被访问过的页被释放

pl[MinPn].pfn=-1;//最久没被访问过的页被换出主存

pl[MinPn].time=-1;//最久没被访问过的页的访问时间置为无效

free_head->next=NULL;

}

pl[page[i]].pfn=free_head->pfn;

//有空闲页面,把相应的页面换入主存,并把pfn改为相应的帧号

pl[page[i]].time=CurrentTime;//令访问时间为当前系统时间

free_head=free_head->next;//减少一个空闲页面

}

else

pl[page[i]].time=CurrentTime;//命中则刷新该单元的访问时间

CurrentTime++;//系统当前时间加

}

printf("%6.3f\t",1-(float)diseffect/320);

return0;

}

九、实验体会

1.通过本次操作系统存储实验,使我对操作系统这门课程有了更进一步的认识和了解,通过模拟实现请求页式存储管理的几种基本页面置换算法,了解虚拟储技术的特点。

通过对页面、页表、地址转换和页面置换过程的模拟,加深对请求调页系统的原理和实现过程的理解。

2.在本次实验过程中,用到了许多C语言的基本知识和操作系统的基本原理,是对平时所学知识的一次考验,尽管这些知识都学过,但运用到实际时,却不知从何下手,而且错误不断,往往为了找一个错误而花了大量的时间,这是专业知识掌握不够,缺乏实践动手能力的表现。

通过不断的纠正错误,上网查找相关资料,以及请教老师,终于完成了本次实验。

在实验的过程中我发现了许多自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,以后还要多加努力。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 其它

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2