模拟可变分区存储管理的内存分配(C)

3/8/2017来源:ASP.NET技巧人气:1203

要求:

系统根据申请者的要求,按照一定的分配策略分析内存空间的使用情况,找出能满足请求的空闲区,分给申请者;当程序执行完毕或主动归还内存资源时,系统要收回它所占用的内存空间或它归还的部分内存空间,主存分配算法使用最坏适应分配算法。

程序运行时根据文件内容初始化空闲区表,文件内容为每行两项:起始地址 长度 中间以逗号隔开,文件内容如下:

10,3 13,4 17,2 30,8 38,7

可变分区存储管理的内存分配方案一般采用"已分配区表"和"空闲区表"来记录主存已分配和未分配的情况,本例中采用单向链表方式来表示两种结构。

分配内存时:从"空闲区表"中找出一项能满足申请空间的记录,然后分割该项,如果分割出剩余空间,则将剩余空间重新放入"空闲区表"中,同时产生一个"已分配区记录项",该记录的长度为申请的空间大小,起始地址为分割的"空闲区"项的起始地址。并将该记录插入到"已分配区表"中。

回收作业内存时:删除该作业在"已分配区表"中的记录项,并按该项的地址和长度创建一个"空闲区"记录,遍历"空闲区表",如果存在上边界相邻或者下边界相邻的记录项,则合并两者(无相邻区块,不需要做任何操作),最后将该记录插入到"空闲区表"中,并使之满足降序条件。

空闲区表数据结构:

//空闲区表
struct free_link
{
	int saddr;//起始地址
	int len;//长度
	int flag;//标志
	struct free_link *next;
};
已分配区表数据结构:

//已分配区表
struct alloc_link
{
	int saddr;//起始地址
	int len;//长度
	int work;//作业名
	struct alloc_link *next;
};

最坏适应分配算法:

空闲区表中每个记录项按照长度递减的顺序排列,当需要分配空间时,只需要从表中取出第一项,然后为任务分割空间即可,如果分割后有剩余空间则将剩余部分再次插入空闲区表中,并重新调整表中记录项,使得满足按照长度递减顺序。

分配内存流程图:

内存回收流程图:

在回收内存时,会涉及到回收的空闲块可能会与"空闲区表"中的某个记录项上边界相邻或者下边界相邻或者上下边界都有相邻的空闲块,这时候就需要合并要回收的记录块和已有的空闲块,本例中采用的方式是:先根据要回收的"已分配区表"中的记录项A,生成一个地址和长度相同的空闲块记录B,然后遍历"空闲区块表",发现有上边界相邻的记录项C,则修改B的起始地址为C记录中的起始地址,长度为B块的长度+C块的长度,然后从链表中删除记录C,继续遍历,如果发现有下边界相邻的记录D,则再修改C的长度为原有长度+D的记录长度,从链表中再把记录D删除,这样直到遍历到链表尾部。此时4中不同情况都已经包含(上边界相邻、下边界相邻,上下边界同时相邻、无相邻),只需要将记录B插入到"空闲区表"中即可。

空闲块合并核心代码:

        //空闲块头指针 
	fp = free_head;
	while(fp->next != NULL)
	{
		//上边界相同 
		if((fp->next->saddr + fp->next->len) == fitem->saddr)
		{
			//上边界与待回收的空间边界进行合并 
			fitem->saddr = fp->next->saddr;
			fitem->len = fp->next->len + fitem->len;
			//释放原有空闲块的内存 
			tmp_item = fp->next;
			fp->next = tmp_item->next;
			tmp_item->next = NULL;
			free(tmp_item);
			tmp_item = NULL;
		}
		
		if((fitem->saddr + fitem->len) == fp->next->saddr)
		{
			//下边界与待回收的空间边界合并 
			fitem->len = fitem->len + fp->next->len;
			//释放原有空闲块内存
			tmp_item = fp->next;
			fp->next = tmp_item->next;
			tmp_item->next = NULL;
			free(tmp_item);
			tmp_item = NULL;
		}
		
		//如果已经遍历到链尾则跳出 
		if(fp->next == NULL)
		{
			break;
		}
		
		fp = fp->next; 
	}
	
	//重新调整空闲区表,按空间递减顺序排列
	fp = free_head;
	while(fp->next != NULL)
	{
		if(fp->next->len <= fitem->len)
		{
			break;
		}
		fp = fp->next;
	}
	
	fitem->next = fp->next;
	fp->next = fitem;

空闲块合并示意图如下:

空闲区表和已分配区表在分配和回收过程中变化效果图:

代码示例