一、实验内容
编写一个内存动态分区分配模拟程序,模拟内存的分配和回收的完整过程。
二、实验目的
主存的分配和回收的实现与主存储器的管理方式有关的,通过本实验帮助学生理解在可变分区管理方式下应怎样实现主存空间的分配和回收。
三、实验原理
模拟在可变分区管理方式下采用最先适应算法实现主存分配和回收。
(1)可变分区方式是按作业需要的主存空间大小来分割分区的。当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入。随着作业的装入、撤离,主存空间被分成许多个分区,有的分区被作业占用,而有的分区是空闲的。例如:
操作系统 |
||
作业1 |
||
作业3 |
||
空闲区 |
||
作业2 |
||
空闲区
|
为了说明哪些区是空闲的,可以用来装入新作业,必须要有一张空闲区说明表,格式如下:
|
起 址 |
长 度 |
状 态 |
第一栏 |
14 K |
12 K |
未 分 配 |
第二栏 |
32 K |
96 K |
未 分 配 |
M |
M |
M |
M |
|
|
|
其中,起址——指出一个空闲区的主存起始地址。
长度——指出从起始地址开始的一个连续空闲的长度。
状态——有两种状态,一种是“未分配”状态,指出对应的由起址指出的某个长度的区域是空闲区。
(2) 当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的空闲区。有时找到的空闲区可能大于作业需要量,这时应把原来的空闲区变成两部分:一部分分给作业占用;另一部分又成为一个较小的空闲区。为了尽量减少由于分割造成的空闲区,而尽量保存高地址部分有较大的连续空闲区域,以利于大型作业的装入。为此,在空闲区说明表中,把每个空闲区按其地址顺序登记,即每个后继的空闲区其起始地址总是比前者大。
(3) 采用最先适应算法(顺序分配算法)分配主存空间。
按照作业的需要量,查空闲区说明表,顺序查看登记栏,找到第一个能满足要求的空闲区。当空闲区大于需要量时,一部分用来装入作业,另一部分仍为空闲区登记在空闲区说明表中。
由于本实验是模拟主存的分配,所以把主存区分配给作业后并不实际启动装入程序装入作业,而用输出“分配情况”来代替。
(4) 当一个作业执行结束撤离时,作业所占的区域应该归还,归还的区域如果与其它空闲区相邻,则应合成一个较大的空闲区,登记在空闲区说明表中。
(5) 请按最先适应算法设计主存分配和回收的程序。假设初始时主存中没有作业,现按下面序列进行内存的申请与释放:
作业1申请300K,作业2申请100K,作业1释放300K,作业3申请150K,
作业4申请30K, 作业5申请40K, 作业6申请60K, 作业4释放30K。
动态内存分配有四种分配方式,本次实验采用首次适应算法
①打印分区表的时候,只需遍历一遍二叉树,然后输出度为0的节点(没有孩子的节点)
②作业完成后,释放空间时,通过插入时候给的作业名称来遍历、寻找到该节点,将其状态修改为free即可
注意:
还有就是释放后,空闲区的合并问题。由于本次实验所插入、释放作业后,无需合并,这点在本次实验忽略(虽然题目有要求。。)
//动态内存分配
#include
int temp=0;//定义一个全局变量!这个变量起很大作用
typedef struct _BiTNode//定义 表 的结构体
{
int address;//首地址
int length;//空闲区长度
bool state;//区域状态 “1”表示已分配, “0”表示未分配
int homework; //作业名
struct _BiTNode *lchild;//指向左孩子的指针
struct _BiTNode *rchild;//右孩子
}BiTNode,*pBiTree;
void Init_BiTree(pBiTree l)
{
l->address = 5;
l->length = 507;
l->state = 0;
l->homework=NULL;
l->lchild = NULL;
l->rchild = NULL;
printf("初始化完成!\n");
}
int Print(pBiTree p)
{
printf("\n\t\t%d\t%d\t",p->address,p->length);
if(p->state==1)
printf("Busy \t");
else
printf("Free \t");
if(p->homework!=0)
printf("%d\n",p->homework);
else
printf("\n");
}
//先序遍历
void PreOrder(pBiTree p)
{
if(p != NULL)
{
if(!p->lchild&&!p->rchild)
Print(p); //输出该结点
PreOrder(p->lchild); //遍历左子树
PreOrder(p->rchild); //遍历右子树
}
}
void Insert_PreOrder(pBiTree p,int length,int homework)//插入新作业
{
if(p != NULL)
{
if((p->state==0)&&(lengthlength)&&(!p->lchild)&&(!p->rchild)&&temp==0)//判断节点是否有左右孩子,是否小于空闲区长度,是否状态为0(表示区域无作业运行)
{
pBiTree x1 =new BiTNode;//进行插入,动态申请两个空间 x1,x2
pBiTree x2 =new BiTNode;
x1->homework=homework;//x1为作业
x2->homework=NULL;//x2为剩余的空闲区
x1->address=p->address;//把原空闲区的首地址给作业的首地址
x1->state=1;//作业的状态改为1
x1->length=length;//作业的长度为传入的长度
x2->address=x1->address+length;//新空闲区的首地址为 x1首地址与x1长度之和
x2->length=p->length-x1->length;
p->lchild=x1;
p->rchild=x2;
x2->state=0;
x1->lchild=NULL;
x1->rchild=NULL;
x2->rchild=NULL;
x2->lchild=NULL;
temp=1;
}
else
{
Insert_PreOrder(p->lchild,length,homework); //遍历左子树
Insert_PreOrder(p->rchild,length,homework); //遍历右子树
}
}
}
void Delect_PreOrder(pBiTree p,int homework) //遍历修改,将状态修改为0。即为空闲区
{
if(p != NULL)
{
if(p->homework==homework)//当查询到作业名相同的作业。进行修改
{
p->homework=NULL;//将作业名修改为空
p->state=0;//将作业名状态修改为空闲
}
Delect_PreOrder(p->lchild,homework); //遍历左子树
Delect_PreOrder(p->rchild,homework); //遍历右子树
}
}
int main()
{
BiTNode l;
Init_BiTree(&l);
//初始化
printf("\n 初始化:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//插入作业1
temp=0;
Insert_PreOrder(&l,300,1);
printf("\n插入作业1:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//插入作业2
temp=0;
Insert_PreOrder(&l,100,2);
printf("\n插入作业2:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//释放作业1
Delect_PreOrder(&l,1);
printf("\n释放作业1:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//插入作业3
temp=0;
Insert_PreOrder(&l,150,3);
printf("\n插入作业3:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//插入作业4
temp=0;
Insert_PreOrder(&l,30,4);
printf("\n插入作业4:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//插入作业5
temp=0;
Insert_PreOrder(&l,40,5);
printf("\n插入作业5:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//插入作业6
temp=0;
Insert_PreOrder(&l,60,6);
printf("\n插入作业6:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
//释放作业4
Delect_PreOrder(&l,4);
printf("\n释放作业4:\t首地址\t长度\t状态\t作业名\n");
PreOrder(&l);
return 0;
}