实验三存储管理实验.docx
《实验三存储管理实验.docx》由会员分享,可在线阅读,更多相关《实验三存储管理实验.docx(25页珍藏版)》请在冰豆网上搜索。
实验三存储管理实验
实验三存储管理实验
一. 目的要求:
1、通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解。
熟悉虚存管理的各种页面淘汰算法。
2、通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。
二.例题
设计一个请求页式存储管理方案。
并编写模拟程序实现之。
产生一个需要访问的指令地址流。
它是一系列需要访问的指令的地址。
为不失一般性,你可以适当地(用人工指定地方法或用随机数产生器)生成这个序列,使得50%的指令是顺序执行的。
25%的指令均匀地散布在前地址部分,25%的地址是均匀地散布在后地址部分。
为简单起见。
页面淘汰算法采用FIFO页面淘汰算法,并且在淘汰一页时,只将该页在页表中抹去。
而不再判断它是否被改写过,也不将它写回到辅存。
具体的做法可以是:
产生一个需要访问的指令地址流;
指令合适的页面尺寸(例如以1K或2K为1页);
指定内存页表的最大长度,并对页表进行初始化;
每访问一个地址时,首先要计算该地址所在的页的页号,然后查页表,判断该页是否在主存——如果该页已在主存,则打印页表情况;如果该页不在主存且页表未满,则调入一页并打印页表情况;如果该页不足主存且页表已满,则按FIFO页面淘汰算法淘汰一页后调入所需的页,打印页表情况;逐个地址访问,直到所有地址访问完毕。
存储管理算法的流程图如下:
三. 实验题:
1、设计一个固定式分区分配的存储管理方案,并模拟实现分区的分配和回收过程。
可以假定每个作业都是批处理作业,并且不允许动态申请内存。
为实现分区的分配和回收,可以设定一个分区说明表,按照表中的有关信息进行分配,并根据分区的分配和回收情况修改该表。
#include
#include
#include
#include
#defineNUM4
#definealloMemory(type)(type*)malloc(sizeof(type))
structpartiTab
{
intno;
intsize;
intfirstAddr;
charstate;
}parTab[NUM];
typedefstructpartiTabPARTITAB;
typedefstructjcb
{
charname[10];
intsize;
structjcb*link;
}JCB;
typedefstruct
{
JCB*front,*rear;
}jcbQue;
jcbQue*jcbReadyQue;
voidAllocateMemory(intsize);
voidcreateTab();
voidcheckTab();
voidrecycleMemory(inti);
voidAllocateMemory(intsize)
{
inti;
intn=0;
for(i=0;i{
PARTITABp=parTab[i];
if(p.state=='N'&&p.size>size)
{
parTab[i].state='Y';
n=1;
break;
}
}
if(n==0)
{
printf("内存大小是%d\t",size);
printf("无法分配内存!
\n");
}
else
{
printf("内存大小是%d\t",size);
printf("装入内存成功!
\n");
}
}
voidcreateTab()
{
parTab[0].no=0;
parTab[0].size=12;
parTab[0].firstAddr=20;
parTab[0].state='N';
parTab[1].no=1;
parTab[1].size=32;
parTab[1].firstAddr=32;
parTab[1].state='N';
parTab[2].no=2;
parTab[2].size=64;
parTab[2].firstAddr=64;
parTab[2].state='N';
parTab[3].no=3;
parTab[3].size=128;
parTab[3].firstAddr=128;
parTab[3].state='N';
}
voidcheckTab()
{
inti;
printf("分区号\t大小\t起址\t状态\n");
for(i=0;i{
printf("%d\t",parTab[i].no);
printf("%d\t",parTab[i].size);
printf("%d\t",parTab[i].firstAddr);
printf("%c\t",parTab[i].state);
printf("\n");
}
}
voidrecycleMemory(inti)
{
parTab[i-1].state='N';
}
intmain(intargc,char*argv[])
{
inti;
intk=1+rand()%100;
printf("****固定式分区分配存储管理******\n");
createTab();
checkTab();
printf("请按任意键继续:
\n");
getchar();
printf("一次装入多个作业:
\n");
for(i=0;i{
AllocateMemory(k);
k=1+rand()%100;
}
checkTab();
printf("请按任意键继续:
\n");
getchar();
printf("若继续装入作业\n");
k=1+rand()%100;
AllocateMemory(k);
checkTab();
printf("请按任意键继续:
\n");
getchar();
printf("若有一个作业完成\n");
k=rand()%4;
recycleMemory
(2);
checkTab();
printf("继续装入作业\n");
k=1+rand()%100;
AllocateMemory(k);
checkTab();
return0;
}
截图显示为:
2、设计一个可变式分区分配的存储管理方案。
并模拟实现分区的分配和回收过程。
对分区的管理法可以是下面三种算法之一:
首次适应算法
循环首次适应算法
最佳适应算法
#include
#include
#include
#include
#definen10
#definem10
#defineminisize100
struct
{
floataddress;
floatlength;
intflag;
}used_table[n];
struct
{
floataddress;
floatlength;
intflag;
}free_table[m];
voidallocate(charJ,floatxk)
{
inti,k;
floatad;
k=-1;
for(i=0;iif(free_table[i].length>=xk&&free_table[i].flag==1)
if(k==-1||free_table[i].lengthk=i;
if(k==-1)
{
printf("无可用空闲区\n");
return;
}
if(free_table[k].length-xk<=minisize)
{
free_table[k].flag=0;
ad=free_table[k].address;
xk=free_table[k].length;
}
else
{
free_table[k].length=free_table[k].length-xk;
ad=free_table[k].address+free_table[k].length;
}
i=0;
while(used_table[i].flag!
=0&&ii++;
if(i>=n)
{
printf("无表目填写已分分区,错误\n");
if(free_table[k].flag==0)
free_table[k].flag=1;
else
{
free_table[k].length=free_table[k].length+xk;
return;
}
}
else
{
used_table[i].address=ad;
used_table[i].length=xk;
used_table[i].flag=J;
}
return;
}
voidreclaim(charJ)
{
inti,k,j,s,t;
floatS,L;
s=0;
while((used_table[s].flag!
=J||used_table[s].flag==0)&&ss++;
if(s>=n)
{
printf("找不到该作业\n");
return;
}
used_table[s].flag=0;
S=used_table[s].address;
L=used_table[s].length;
j=-1;k=-1;i=0;
while(i{
if(free_table[i].flag==1)
{
if(free_table[i].address+free_table[i].length==S)k=i;
if(free_table[i].address==S+L)j=i;
}
i++;
}
if(k!
=-1)
if(j!
=-1)
{
free_table[k].length=free_table[j].length+free_table[k].length+L;
free_table[j].flag=0;
}
else
free_table[k].length=free_table[k].length+L;
else
if(j!
=-1)
{
free_table[j].address=S;
free_table[j].length=free_table[j].length+L;
}
else
{
t=0;
while(free_table[t].flag==1&&tt++;
if(t>=m)
{
printf("主存空闲表没有空间,回收空间失败\n");
used_table[s].flag=J;
return;
}
free_table[t].address=S;
free_table[t].length=L;
free_table[t].flag=1;
}
return;
}
intmain()
{
inti,a,b=4;
floatxk;
charJ;
free_table[0].address=10240;
free_table[0].length=10240;
free_table[0].flag=1;
for(i=1;ifree_table[i].flag=0;
for(i=0;iused_table[i].flag=0;
while(b==4)
{
printf("请选择功能项:
\n");
printf("0、退出!
\n");
printf("1、分配主存!
\n");
printf("2、回收主存!
\n");
printf("3、显示主存!
\n");
printf("选择功项(0~3):
\n");
scanf("%d",&a);
switch(a)
{
case0:
exit(0);
case1:
printf("输入作业名作业所需长度:
");
scanf("%*c%c%f",&J,&xk);
allocate(J,xk);
break;
case2:
printf("输入要回收分区的作业名");
scanf("%*c%c",&J);
reclaim(J);
break;
case3:
printf("输出空闲区表:
\n起始地址分区长度标志\n");
for(i=0;iprintf("%6.0f%9.0f%6d\n",free_table[i].address,free_table[i].length,free_table[i].flag);
printf("按任意键,输出已分配区表\n");
getch();
printf("输出已分配区表:
\n起始地址分区长度标志\n");
for(i=0;iif(used_table[i].flag!
=0)
printf("%6.0f%9.0f%6c\n",used_table[i].address,used_table[i].length,used_table[i].flag);
else
printf("%6.0f%9.0f%6d\n",used_table[i].address,used_table[i].length,used_table[i].flag);
break;
default:
printf("没有该选项\n");
break;
}
}
return0;
}
截图得:
3、编写并调试一个段页式存储管理的地址转换的模拟程序。
首先设计好段表、页表,然后给出若干个有一定代表性的地址,通过查找段表页表后得到转换的地址。
要求打印转换前的地址,相应的段表,页表条款及转换后的地址,以便检查。
#include
#include
usingnamespacestd;
typedefstructQuick
{
intqs;//快表段号
intqp;//快表页号
intqb;//快表段号
}Quick;
typedefstructData
{
intnum;
stringstr;
}Data;
typedefstructPage
{
intnum;
intflag;
intblock;
}Page;
typedefstructStack
{
intnum;
intflag;
intplen;
intpsta;
}Stack;
typedefstructStare
{
intssta;
intslen;
}Stare;
Stackss[10];
Starest;
Datawork[20];
Quickqu;
Pagepage[5][5];
boolmenuflag=0;
intbbs;
intbs;
voidmenu();
voidstart();
voidchange();
voidmenu()
{
cout<<"段页式存储管理的地址转换的模拟程序"<cout<<"请选择相应的序号:
"<cout<<"1、初始化表"<cout<<"2、物理地址转换"<cout<<"3、退出"<intmenu1;
cin>>menu1;
if(menu1!
=1&&menu1!
=2&&menu1!
=3)
{
cout<<"请输入正确的选项"<menu();
}
switch(menu1)
{
case1:
{
menuflag=1;
start();
break;
}
case2:
{
if(menuflag==0)
{
cout<<"请初始化表"<menu();
}
change();
break;
}
case3:
return;
}//switch
}
voidstart()
{
cout<<"请输入内存大小(K)"<cin>>bs;
cout<<"请输入内存块的大小(k)"<cin>>bbs;
intblocknum;
blocknum=bs/bbs;
cout<<"内存一共被分为"<cout<<"请输入进程个数"<intpn;
cin>>pn;
intsums=0;
for(intpn1=0;pn1{
cout<<"请输入第"<intppn;
cin>>ppn;
sums+=ppn;
}
for(intss1=0;ss1{
cout<<"请输入段表第"<段号,状态,页表长度,页表始址"<cin>>ss[ss1].num>>ss[ss1].flag>>ss[ss1].plen>>ss[ss1].psta;
cout<<"请初始化第"<for(intsss1=0;sss1{
page[ss1][sss1].num=sss1;
cout<<"请输入该页表第"<cin>>page[ss1][sss1].num>>page[ss1][sss1].flag>>page[ss1][sss1].block;
}
}
cout<<"初始化段表寄存器的段表始址"<cin>>st.ssta;
st.slen=sums;
cout<<"我们对物理地址的每一块用字符串进行简单的初始化"<for(intbn=0;bn{
work[bn].num=bn;
cout<<"请输入第"<cin>>work[bn].str;
}
cout<<"初始化快表只有一个"<cout<<"请输入要作为快表的段号和页号"<cin>>qu.qb>>qu.qp;
while(ss[qu.qb].flag!
=1||page[qu.qb][qu.qp].flag!
=1)
{
cout<<"该页不在内存请输入一页在内存中的作为快表,请输入要作为快表的段号和页号"<cin>>qu.qb>>qu.qp;
}
qu.qs=page[qu.qb][qu.qp].block;
menu();
}
voidchange()
{
cout<<"请输入要转化的逻辑地址,段号,段内页号,页内偏移地址"<intsnum,pnum,dnum;
cin>>snum>>pnum>>dnum;
if(snum==qu.qb&&pnum==qu.qp)
{
cout<<"快表命中"<<"对应块号是"<cout<<"该块中作业数据是"<cout<<"物理地址是"<menu();
}
else
{
cout<<"快表没有命中,访问段表寄存器"<intssnum;
ssnum=st.ssta+snum;
if(ssnum>st.slen-1)
{
cout<<"越界中断"<menu();
}
else
{
if(ssnum>=0&&ssnum<=st.slen-1)
{
cout<<"段表有效"<if(ss[ssnum].flag==0)
{
cout<<"缺段中断"<menu();
}
else
{
if(pnum>ss[ssnum].plen-1)
{
cout<<"缺页中断"<menu();
}
else
{
if(pnum>=0&&pnum<=ss[ssnum].plen-1)
{
if(page[ssnum][pnum].flag==0)
{
cout<<"缺页中断"<menu();
}
else
{
cout<<"找到该页"<<"查询页表后对应块号"<cout<<"该块内存的数据是"<cout<<"转化得到的物理地址是:
"<menu();
}
}
}
}
}
}
cout<<"此时将此项内容添加到快表里面"<}
}
intmain()
{
menu();
return0;
}
截图可以得到:
四.实验总结
这次的实验对于我来说还是比较难的,几乎每次都是这样,看书的时候能够理解书上的讲解,也大概了解存储管理的过程和原理,但是在编写代码的时候却总是一团迷雾,不知道从哪里下手才好,我从网上找了代码,然后阅读理解了,但是代码里面有很多错误,而且有的过程也是错的,我就改正了一下。
就比如说第一题来说,网上代码是将分区说明表是采取循环的方式进行设置,但是我觉得不太好,所以就以四个为例逐个的进行设置,虽然比较麻烦而且代码比较冗余,但是这样可以设置不同大小的固定