可变分区管理实现内存的动态申请与释放
可变分区管理是属于连续存储管理的实现方法,这种方法按照作业大小划分分区,划分的时间、大小和位置都是动态的,是一种动态分区方法。
题目
以可变分区管理实现内存的动态申请与释放,限定最大分区数和存储空间大小,每次操作后显示分区信息。当申请内存时,从中选取满足要求的空闲区,并划出一个分区;当不满足要求或超出分区数限制时,提示分配失败;当释放内存时,回收相应内存区,并合并成一个新的空闲区。
思路
由我们去实现底层的内存分配机制还是有些困难的,这里只是用c语言实现模拟可变分区管理的这种机制。为了模拟这种机制主要需要实现以下内容:
- 分区和分区表数据结构的表示
- 分区的查找与分配算法
- 分区的释放与合并分区的操作
一、数据定义
采用链表的结构存储分区信息,这里可以用空闲和占用两个链表分别存储空闲分区和已分配的分区。当然,如果不想操作那么复杂的话也可以直接用一条链表搞定,只需要在节点定义时多加一个属性来判断分区是否空闲即可。
#define MaxParts 5//定义分区最大数
#define Memaxsize 1024//定义内存大小
typedef struct Part//分区信息
{
int startAddress;//开始地址
int length;//分区长度
bool freee;//是否空闲
struct Part *next;//下一个分区
}Part;
Part partFirst={
0,Memaxsize,true,NULL};//初始化分区链表首项
typedef struct Distribution//分配结果
{
bool give;//是否获得分区
Part *part;//分区信息
int errorType;//错误类型 1 分区数过多 2 无足够大的分区
}Distribution;
二、分区的查找与分配
当由用户提出内存申请时,需要对链表进行查找,找到符合要求的分区分配给用户,分区分配有很多种算法,如下:
- 最先(首次)适应分配算法:
从链首顺序查找,找到第一个满足要求的分区即可开始分配。该算法要求空闲分区链以地址递增顺序链接。 - 下次(循环首次)适应分配算法:
每次不从链首查找,而是从上次找到的空闲分区的下一个分区开始查找。 - 最优适应分配算法:
每次从链首顺序查找,分配能满足要求的最小分区。 通常将空闲分区按照大小从小到大排列。 - 最坏适应分配算法:
每次从链首顺序查找,分配能满足要求的最大分区。 - 快速适应分配算法
为经常用到的长度的空闲区设置单独的链表。
这里采用简单高效的最先(首次)适应分配算法。
for(Part *temp = &partFirst;temp != NULL;temp = temp->next)//遍历内存分区表
{
if (temp->freee && temp->length > length)//找到足够大的分区
{
if (countPart + 1 > MaxParts) //已经达到最大分区数目,拒绝分配
{
errorType = 1;
break;
}
else //可以分配
countPart++;
temp->freee = false;//将分区标记为已分配
int tempLength = temp->length;
temp->length = length;//分区长度为申请长度
Part * tempNext = temp->next;//新建一个分区节点插入到当前分区节点之后
tempNext = (Part *)malloc(sizeof(Part));
tempNext->startAddress=temp->startAddress + temp->length;
tempNext->length=tempLength - length;
tempNext->freee=true;
tempNext->next=temp->next;
temp->next=tempNext;//这些步骤主要是为分割之后剩余的部分新建一个分区插入到分区链中,其中步骤不再赘述注释
disPart = temp;
dised = true;
break;
}
else if (temp->freee && temp->length == length)//大小相等直接修改空闲值
{
temp->freee = false;//这种情况不需要分割分区,直接分配
disPart = temp;
dised = true;
break;
}
if(temp->next==NULL)//没有找到满足大小的分区,返回错误信息
errorType = 2;
}
三、分区释放与分区合并
分区释放主要考虑以下四种情况:
- 左右不空闲
| 进程A | 进程X | 进程B | - 右分区空闲
| 进程A | 进程X | 空闲 | - 左分区空闲
| 空闲 | 进程X | 进程B | - 两侧分区空闲
| 空闲 | 进程X | 空闲 |
代码如下:
for(Part *temp = &partFirst;temp != NULL;temp = temp->next)//遍历找释放分区的前一个分区
{
if (i+1 == n && temp->next != NULL)
{
if (temp->next->next != NULL && temp->next->next->freee == true) //后一个为空闲
{
if (temp->freee) //前后都为空闲,合并三个分区
{
Part *center = temp->next;
Part *right = temp->next->next;
Part *tempNext = temp->next->next->next;
temp->length += temp->next->length + temp->next->next->length;
temp->next = tempNext;
free(center);
center=NULL;
free(right);
right=NULL;
}
else //后面一个为空闲,合并两个分区
{
Part *right = temp->next->next;
Part *tempNext = temp->next->next->next;
temp->next->length += temp->next->next->length;
temp->next->next = tempNext;
temp->next->freee = true;
free(right);
right=NULL;
}
}
else //后一个不为空闲
{
if (temp->freee) //前一个为空闲,合并两个分区
{
Part *center = temp->next;
Part *tempNext = temp->next->next;
temp->length += temp->next->length;
temp->next = tempNext;
free(center);
center=NULL;
}
else//前后都不为空,只释放分区
temp->next->freee = true;
}
freee = true;
break;
}
else if(n==1)//特例判断,释放第一项,仅观察其后一分区是否为空
{
if(temp->next->freee)//释放分区并合并
{
Part *right = temp->next;
Part *tempNext = temp->next->next;
temp->length += temp->next->length;
temp->next = tempNext;
temp->freee = true;
free(right);
right=NULL;
}
else//只释放分区
temp->freee = true;
freee = true;
break;
}
i++;
}
四、其他
上述已经完成了模拟实现可变分区管理的机制主体部分,适当组织一下交互操作流程即可。
这里给出参考代码:
void Menu()
{
int selected;
int value;
Distribution ret;
bool quit = false;
while (!quit)
{
printf("可变分区存储管理\n");
printf("1、申请内存\n");
printf("2、释放内存\n");
printf("3、退 出\n");
scanf("%d",&selected);
switch (selected)
{
case 1: printf("请输入申请内存大小:\n");
scanf("%d",&value);
ret = requestMe(value);
if (ret.give)
{
printf("\n分配成功.\n");
}
else
{
printf("\n分配失败.\n");
switch(ret.errorType)
{
case 1:
printf("%s.\n", "分区数达到限制");
break;
case 2:
printf("%s.\n", "没有足够大的分区可以分配");
break;
case 0:default:break;
}
}
break;
case 2:
printf("请输入要释放的分区序号:\n");
scanf("%d",&value);
freeMe(value);
break;
case 3:
quit = true;
break;
default:
break;
}
if(!quit)
showMe();//这是一个简单的遍历链表的函数
}
}