实验三 存储管理实验--starof

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验三存储管理实验
一. 目的要求:
1、通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解。

熟悉虚存管理的各种页面淘汰算法。

2、通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。

二 . 实验题:
1、设计一个固定式分区分配的存储管理方案,并模拟实现分区的分配和回收过程。

可以假定每个作业都是批处理作业,并且不允许动态申请内存。

为实现分的分配和回收,可以设定一个分区说明表,按照表中的有关信息进行分配,并根据分区的分配和回收情况修改该表。

1.1、算法描述
本算法将内存的用户区分成大小相等的四个的分区,设一张分区说明表用来记录分区的大小、起始地址和分区的状态,当系统为某个作业分配主存空间时,根据所需要的内存容量,在分区表中找到一个足够大的空闲分区分配给它,然后将此作业装入内存。

如果找不到足够大的空闲分区,则这个作业暂时无法分配内存空间,系统将调度另一个作业。

当一个作业运行结束时,系统将回收改作业所占据的分区并将该分区改为空闲。

1.2、程序运行结果:
1.3程序代码:(C语言描述)
#include <stdio.h>
#include <stdio.h>
#include<math.h>
#include<stdlib.h>
#define NUM 4
#define alloMemory(type) (type*)malloc(sizeof(type))
struct partiTab
{
int no;
int size;
int firstAddr;
char state;
}parTab[NUM];
typedef struct partiTab PARTITAB;
typedef struct jcb { /*定义作业控制块JCB ,部分信息省略*/ char name[10]; //作业名
int size; //作业大小
struct jcb* link; //链指针
}JCB;
typedef struct
{
JCB *front,*rear;
}jcbQue;
jcbQue *jcbReadyQue;
void AllocateMemory(int size);
void createTab();
void checkTab();
void recycleMemory(int i);
void AllocateMemory(int size)
{
int i;
for(i=0;i<NUM;i++)
{
PARTITAB p=parTab[i];
if(p.state='N' && p.size>size)
parTab[i].state='Y';
else
printf("没有空闲分区,无法分配内存!\n");
}
}
void createTab()
{int i;
for( i=1;i<=NUM;i++)
{
//getPartiTab(PARTITAB);
parTab[i-1].no=i;
parTab[i-1].size=20;
parTab[i-1].firstAddr=21;
parTab[i-1].state='N';
}
}
void checkTab()
{
int i;
printf("分区号\t大小\t起址\t状态\n");
for(i=0;i<NUM;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");
}
}
void recycleMemory(int i)
{
parTab[i-1].state='N';
}
int main(int argc, char* argv[])
{
int i;
printf("****固定式分区分配存储管理******\n");
createTab();
checkTab();
printf("请按任意键继续:\n");
getchar();
printf("每个分区装入一道作业:\n");
for(i=0;i<NUM;i++)
{
AllocateMemory((i+1)*3);
}
checkTab();
printf("请按任意键继续:\n");
getchar();
printf("假如一段时间后,其中一个作业结束,回收给它分配的分区(假如该作业在第2分区)\n");
recycleMemory(2);
checkTab();
printf("请按任意键继续:\n");
getchar();
printf("接着,从外存后备作业队列中选择一个作业装入该分区(假如该作业大小为10)\n");
AllocateMemory(10);
checkTab();
return 0;
}
2、设计一个可变式分区分配的存储管理方案。

并模拟实现分区的分配和回收过程。

对分区的管理法可以是下面三种算法之一:
首次适应算法
循环首次适应算法
最佳适应算法
2.1:算法分析:
2.1.1、可变分区管理是指在处理作业过程中建立分区,使分区大小正好适合作业的需求,
并且分区个数是可以调整的。

当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入,作业等待。

2.1.2、当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的
空闲区。

有时找到的空闲区可能大于作业需要量,这时应把原来的空闲区变成两部分:一部分分给作业占用;另一部分又成为一个较小的空闲区,留在空闲区表中。

2.1.3、选择用最佳适应算法实现可变式分区管理,从全部空闲区中找出能满足作业要求
的、且大小最小的空闲分区。

本程序模拟可变式分区管理,所以把主存区分配给作业后并不实际启动装入程序装入作业,而用输出“分配情况”来代替。

2.1.4、当一个作业执行完成撤离时,作业所占的分区应该归还给系统,归还的分区如果
与其它空闲区相邻,则应合成一个较大的空闲区,登记在空闲区说明表中。

2.2:程序运行结果
2.2.1、初始界面:
2.2.2、选择1,可以看到初始时主存初始时均未分配
2.2.3、选择2,输入三个作业:
2.2.4、显示主存和分区表:
2.2.5、输入3回收主存:
2.2.6、再次查看空闲区表和分区表:
2.3:程序源代码(C语言描述,在ColdBlocks 下运行)#include<stdio.h>
#include <dos.h>
#include<stdlib.h>
#include<conio.h>
#define n 10 /*假定系统允许的最大作业数为n,假定模拟实验中n值为10*/
#define m 10 /*假定系统允许的空闲区表最大为m,假定模拟实验中m值为10*/
#define minisize 100 /*空闲分区被分配时,如果分配后剩余的空间小于minisize,则将该空闲分区全部分配,若大于minisize,则切割分配*/
struct
{
float address; /*已分配分区起始地址*/
float length; /*已分配分区长度,单位为字节*/
int flag; /*已分配区表登记栏标志,用"0"表示空栏目*/
} used_table[n]; /*已分配区表*/
struct
{
float address; /*空闲区起始地址*/
float length; /*空闲区长度,单位为字节*/
int flag; /*空闲区表登记栏标志,用"0"表示空栏目,用"1"表示未分配*/ } free_table[m]; /*空闲区表*/
void allocate(char J,float xk) /*给J作业,采用最佳分配算法分配xk大小的空间*/ {
int i,k;
float ad;
k=-1;
for(i=0; i<m; i++) /*寻找空间大于xk的最小空闲区登记项k*/
if(free_table[i].length>=xk&&free_table[i].flag==1)
if(k==-1||free_table[i].length<free_table[k].length)
k=i;
if(k==-1) /*未找到可用空闲区,返回*/
{
printf("无可用空闲区\n");
return;
}
/*找到可用空闲区,开始分配:若空闲区大小与要求分配的空间差小于minisize 大小,则空闲区全部分配;
若空闲区大小与要求分配的空间差大于minisize大小,则从空闲区划出一部分分配*/
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&&i<n) /*寻找空表目*/ i++;
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;
}/*主存分配函数结束*/
void reclaim(char J) /*回收作业名为J的作业所占主存空间*/ {
int i,k,j,s,t;
float S,L;
/*寻找已分配表中对应登记项*/
s=0;
while((used_table[s].flag!=J||used_table[s].flag==0)&&s<n) s++;
if(s>=n) /*在已分配表中找不到名字为J的作业*/
{
printf("找不到该作业\n");
return;
}
/*修改已分配表*/
used_table[s].flag=0;
/*取得归还分区的起始地址S和长度L*/
S=used_table[s].address;
L=used_table[s].length;
j=-1;
k=-1;
i=0;
/*寻找回收分区的空闲上下邻,上邻表目k,下邻表目j*/
while(i<m&&(j==-1||k==-1))
{
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&&t<m)
t++;
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;
}/*主存回收函数结束*/
int main( )
{
printf("***************************************************************\n");
printf(" 可变式分区分配(最佳适应算法)
\n");
printf("
\n");
printf("***************************************************************\n");
int i,a;
float xk;
char J;
/*空闲分区表初始化:*/
free_table[0].address=10240; /*起始地址假定为10240*/
free_table[0].length=10240; /*长度假定为10240,即10k*/
free_table[0].flag=1; /*初始空闲区为一个整体空闲区*/
for(i=1; i<m; i++)
free_table[i].flag=0; /*其余空闲分区表项未被使用*/
/*已分配表初始化:*/
for(i=0; i<n; i++)
used_table[i].flag=0; /*初始时均未分配*/
while(1)
{
printf("功能选择项:\n1。

显示主存\n2。

分配主存\n3。

回收主存\n4。

退出\n");
printf("请选择相应功能1--4 :");
scanf("%d",&a);
switch(a)
{
case 4:
exit(0); /*a=4程序结束*/
case 2: /*a=2分配主存空间*/
printf("输入作业名J和作业所需空间xk: ");
scanf("%*c%c%f",&J,&xk);
allocate(J,xk); /*分配主存空间*/
break;
case 3: /*a=3回收主存空间*/
printf("输入要回收分区的作业名");
scanf("%*c%c",&J);
reclaim(J); /*回收主存空间*/
break;
case 1: /*a=1显示主存情况*/
/*输出空闲区表和已分配表的内容*/
printf("输出空闲区表:\n起始地址分区长度标志\n");
for(i=0; i<m; i++)
printf("%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; i<n; i++)
if(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");
}/*case*/
}/*while*/
return 1;
}
3、编写并调试一个段页式存储管理的地址转换的模拟程序。

首先设计好段表、页表,然后给出若干个有一定代表性的地址,通过查找段表页表后得到转换的地址。

要求打印转换前的地址,相应的段表,页表条款及转换后的地址,以便检查。

3.1程序运行结果
3.1.1程序界面如下:
3.1.2程序运行结果如下:
3.2程序代码如下:
#include<iostream> #include<string> using namespace std;
typedef struct Quick
int qs;//快表段号
int qp;//快表页号
int qb;//快表段号
} Quick;
typedef struct Data
{
int num;//内存的块数
string str;//对应数据块的作业内容,简化起见说明内容为一串字符。

} Data;
//页表
typedef struct Page
{
int num;//页号
int flag;//页状态,即是否在内存。

int block;//该页对应的块号
} Page;
typedef struct Stack
{
int num;//段号
int flag;//段状态
int plen;//页表长度
int psta;//页表始址
} Stack;
//段表寄存器
typedef struct Stare
{
int ssta;//段表始址
int slen;//段表长度
} Stare;
Stack ss[10];////全局变量
Stare st;///////全局变量
Data work[20];//全局变量
Quick qu;//////全局变量
Page page[5][5];
bool menuflag=0;
int bbs;//内存块大小
int bs;//内存大小
void menu();
void start();
void change();
int main()
menu();
return 0;
}
void menu()
{
cout<<"*****段页式存储管理的地址转换的模拟程序*****"<<endl; cout<<"请选择:"<<endl;
cout<<endl;
cout<<" 1、初始化表 "<<endl;
cout<<" 2、物理地址转换 "<<endl;
cout<<" 3、退出 "<<endl;
int menu1;
cin>>menu1;
if(menu1!=1&&menu1!=2&&menu1!=3)
{
cout<<"请输入正确的选项"<<endl;
menu();
}
switch(menu1)
{
case 1:
{
menuflag=1;
start();
break;
}
case 2:
{
if(menuflag==0)
{
cout<<"请初始化表"<<endl;
menu();
}
change();
break;
}
case 3:
return;
}//switch
}
void start()
cout<<"请输入内存大小(K)"<<endl;
cin>>bs;
cout<<"请输入内存块的大小(k)"<<endl;
cin>>bbs;
int blocknum;
blocknum=bs/bbs;
cout<<"内存一共被分为"<<blocknum<<"块,每块"<<bbs<<"k"<<"一共"<<bs<<"k"<<endl;
cout<<"请输入进程个数"<<endl;
int pn;
cin>>pn;
//下面求所有进程的总段数和段表,并为每段创建页表
int sums=0;
for (int pn1=0; pn1<pn; pn1++)
{
cout<<"请输入第"<<pn1<<"个进程的段数"<<endl;
int ppn;
cin>>ppn;
sums+=ppn;
}
for(int ss1=0; ss1<sums; ss1++)
{
cout<<"请输入第"<<ss1<<"个段表数据:段号,状态,页表长度,页表始址"<<endl; cin>>ss[ss1].num>>ss[ss1].flag>>ss[ss1].plen>>ss[ss1].psta;
cout<<"请初始化第"<<ss1<<"段的页表,输入两个数据页表状态和对应块号"<<endl;
for(int sss1=0; sss1<ss[ss1].plen; sss1++)
{
page[ss1][sss1].num=sss1;
cout<<"请输入该段第"<<sss1<<"个页表的页表状态和对应块号"<<endl;
cin>>page[ss1][sss1].flag>>page[ss1][sss1].block;
}
}
//初始化段表寄存器
cout<<"初始化段表寄存器的段表始址"<<endl;
cin>>st.ssta;
st.slen=sums;
//初始化内存中物理地址每一块的数据区
cout<<"简单起见,我们对物理地址的每一块用字符串进行简单的初始化,没有具体到每一物理地址"<<endl;
for (int bn=0; bn<blocknum; bn++)
{
work[bn].num=bn;
cout<<"请输入第"<<bn<<"个内存块里的作业内容"<<endl;
cin>>work[bn].str;
}
//初始化快表
cout<<"简单起见,我们初始化快表只有一个"<<endl;
cout<<"请输入要作为快表的段号和页号"<<endl;
cin>>qu.qb>>qu.qp;
while(ss[qu.qb].flag!=1||page[qu.qb][qu.qp].flag!=1)
{
cout<<"该页不在内存请输入一页在内存中的作为快表,请输入要作为快表的段号和页号"<<endl;
cin>>qu.qb>>qu.qp;
}
qu.qs=page[qu.qb][qu.qp].block;
menu();
}
void change()
{
cout<<"请输入要转化的逻辑地址,段号s,段内页号p,页内偏移地址d(B)"<<endl; int snum,pnum,dnum;
cin>>snum>>pnum>>dnum;
//首先查快表
if(snum==qu.qb&&pnum==qu.qp)
{
cout<<"快表命中"<<"对应块号是"<<qu.qs<<endl;
cout<<"该块中作业数据是"<<work[page[qu.qb][qu.qp].block].str<<endl;
cout<<"物理地址是"<<qu.qs*bbs*1024+dnum<<endl;;
menu();
}
//访问段表寄存器
else
{
cout<<"快表没有命中,访问段表寄存器,段号等于段表始址加上偏移地址"<<endl;
int ssnum;
ssnum=st.ssta+snum;
if(ssnum>st.slen-1)
{
cout<<"越界中断"<<endl;
menu();
}
//访问段表
else
{
if(ssnum>=0&&ssnum<=st.slen-1)
{
//是否缺段
cout<<"段表有效"<<endl;
if(ss[ssnum].flag==0)
{
cout<<"缺段中断"<<endl;
menu();
}
else
{
//查询页表,根据段号查出页表始址,加上段内偏移页数,即得到页表项。

//缺页中断测试
if(pnum>ss[ssnum].plen-1)
{
cout<<"缺页中断"<<endl;
menu();
}
else
{
if(pnum>=0&&pnum<=ss[ssnum].plen-1)
{
if(page[ssnum][pnum].flag==0)
{
cout<<"缺页中断"<<endl;
menu();
}
else
{
cout<<"找到该页"<<"查询页表后对应块号"<<page[ssnum][pnum].block<<endl;
cout<<"该块内存的数据是"<<work[page[ssnum][pnum].block].str<<endl;
cout<<"转化得到的物理地址是:"<<page[ssnum][pnum].block*bbs*1024+dnum<<endl;
menu();
}
}
}
}
} }
}
}
三、实验总结。

相关文档
最新文档