C语言_单连续分区存储管理—-可变分区存储管理实现

Posted 一只特立独行的猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言_单连续分区存储管理—-可变分区存储管理实现相关的知识,希望对你有一定的参考价值。

在学习操作系统时,讲到CPU对内存的寻址,会涉及到内存的管理方式,内存管理方式有如下四种:
1.单连续分区存储管理
2.页式存储管理
3.段式存储管理
4.段页式存储管理

其中,单连续分区存储管理可以分为1.固定分区存储管理2.可变分区存储管理
其中最复杂的是可变分区存储管理,内存管理效果最好,但是实际应用最多的是段页式存储管理。段页式存储管理实现考虑情况较少,实现起来相对简单,但是效率也很高。但是如果明白了可变分区存储管理,应该其他内存管理方式也明白了。

单连续分区存储管理

思想

维护两个数据结构
1.用于存放空闲分区的双向链表
2.是用于存放内存中作业信息的线性表
将内存看成是一个大的块,当有作业申请内存时,就找第一个足够大小的空闲分区,将作业放入该分区,同时更新线性表和链表。如果没有足够大小的空间,就启动主存紧凑(将所有的主存外零头汇聚到高地址处),得到一个大的空闲分区块,然后判断是否满足分配条件。

算法实现

分配内存

只考虑三种情况
|1.作业C不能放入空闲分区。
|2.作业C可以放入空闲分区
___|2.1剩下的内存大小不足以形成内存碎片,直接分配给该作业。
___|2.2.作业C可以放入空闲分区,剩下的内存大小也足以形成内存碎片

void addTable(int name, int size,int addr) 
	//往任务分配表中添加新任务
	for (int i = 0; i < 100; i++) 
		if (tab[i].flag == false) 
			tab[i].name = name;
			tab[i].addr = addr;
			tab[i].length = size;
			tab[i].flag = true;								//该内存块被占用
			return;
		
	

void alterTable() 
	//修改任务分配表
	std::sort(tab, tab + 100, cmp);									//将任务分配表按从大到小的顺序排序
	tab[0].addr = 0;
	for (int i = 1; i < 100; i++) 
		if (!tab[i].flag) break;
		tab[i].addr = tab[i - 1].addr + tab[i - 1].length;		//更改任务起始地址
	

void compactMem(pFreePartition p) 
	//递归将p空闲分区合并到p.next中
	if (p == NULL) 
		return;
	
	if (p->next == NULL) 
		head = p;
		p->back = NULL;
		return;
	
	p->next->size += p->size;										//更改空闲分区的大小
	p->next->address -= p->size;									//更改空闲分区的地址
	compactMem(p->next);
	free(p);

void ffcolection() 
	//模拟分配内存模块
	int size;
	int name;
	bool flag = false;												//用于标识分配了一个完整的分区
	printf("\\n----------模拟分配作业内存模块----------\\n\\n");
	printf("\\n请输入需要分配的作业名:\\n");
	scanf("%d", &name);
	printf("\\n请输入需要分配的内存大小(单位 B):\\n");
	scanf("%d", &size);

	pFreePartition p = head;										//设置指针遍历空闲分区链表

	while (p != NULL) 
		if (p->size > size) 
			//当前内存区满足分配条件
			if (p->size - size > MIN) 
				//分配内存以后的空间满足内存碎片
				addTable(name, size, p->address);					//修改作业分配表
				p->size = p->size - size;							//修改空闲区链表
				p->address += size;
			
			else 
				//分配内存以后的空间不满足内存碎片的条件,直接分配给原进程
				addTable(name, p->size, p->address);
				flag = true;
				if (p == head) 
					//头结点为分区
					head = p->next;									//空闲区链表为空
					free(p);
					p = NULL;
				
				else 
					//非头结点为分区
					p->back->next = p->next;
					free(p);
					p = NULL;
				
			
			break;
		
		//当前内存区不满足内存分配条件
		p = p->next;
	

	if (p == NULL && flag == false) 
		//p==NULL有可能分配了一个完整的分区,有可能没有找到一个分区,flag==fasle标识没有找到一个完整的分区
		//尝试主存紧凑
		//printf("test1:%d\\n", head->address);
		compactMem(head);
		//printf("test2:%d\\n", head->address);
		//更改任务分配表
		alterTable();
		if (head==NULL||head->size < size) 
			printf("无法为任务提供足够内存!!\\n");
		
		else 
			addTable(name, size, head->address);
			head->size -= size;
			head->address += size;
			if (head->size == 0) 
				free(head);
				head = NULL;
			
		
	

释放内存

四种情况:
情况一:
情况2:

情况3:
情况4:

实际上四种情况可以当成两种情况处理,先将空闲内存块插入,最后再进行空闲块整合。

void recolection() 
	//模拟释放内存模块
	int name;														//记录删除的进程名
	int address = -1;													//记录删除的进程地址
	int length;														//记录删除的进程长度
	printf("\\n----------模拟释放内存模块----------\\n\\n");
	printf("\\n请输入要释放的作业名:\\n\\n");
	scanf("%d", &name);

	for (int i = 0; i < 100; i++) 									//任务分配表中删除任务name
		if (name == tab[i].name) 
			address = tab[i].addr;
			length = tab[i].length;
			tab[i].flag = false;
			tab[i].addr = INF;
		
	
	if (address == -1) 
		printf("任务名不存在!!\\n");
		return;
	

	pFreePartition p = head;
	pFreePartition pre = head;

	while (p != NULL) 
		if (p->address > address) 
			//p空闲分区在address之后
			break;
		
		pre = p;
		p = p->next;
	

	if (p == NULL) 
		//释放的任务后无空闲区
		p = (pFreePartition)malloc(sizeof(freePartition));
		p->address = address;
		p->next = NULL;
		p->back = pre;
		p->size = length;
		if (p->back != NULL) 
			//p不是头结点
			p->back->next = p;
		
		else 
			//p是头结点
			head = p;
		
	
	else 
		//释放的任务后有空闲区
		pFreePartition temp = (pFreePartition)malloc(sizeof(freePartition));
		//检测一下p->back是否是空
		temp->next = p;
		temp->back = p->back;
		p->back = temp;
		if (temp->back != NULL) 
			//p不是头结点
			temp->back->next = temp;
		
		else 
			//p是头结点
			head = temp;
		
		
		temp->address = address;
		temp->size = length;
	

/*任务内存恢复测试
	p = head;
	while (p != NULL) 
		printf("test:   address:%d   size:%d\\n", p->address, p->size);
		p = p->next;
	
*/
	p = head->next;
	while (p!=NULL&&p->back!=NULL) 
		//将多个连续的分区合并为一个分区
		if (p->back->address + p->back->size == p->address) 
			//printf("p->address:%d p->size:%d p->next->addreee:%d\\n", p->address, p->size, p->next->address);
			pFreePartition temp = p->back;
			p->size += p->back->size;
			p->address = p->back->address;
			head = p;
			free(temp);
		
		p = p->next;
	
	printf("内存释放完成\\n");

查看内存使用情况和作业管理表使用情况

void seeSimulateMemory() 
	//查看当前模拟内存使用情况
	printf("\\n空闲分区使用情况:\\n\\n");
	pFreePartition p = head;
	while (p != NULL) 
		printf("address:%d   size:%d\\n", p->address,p->size);
		p = p->next;
	
	printf("\\n-----------任务分配情况----------\\n\\n");
	for (int i = 0; i < 100; i++) 
		if (tab[i].flag==true) 
			printf("name:%d   address:%d   length:%d\\n", tab[i].name, tab[i].addr, tab[i].length);
		
	
	printf("空闲分区查看完成");

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<algorithm>

#define debug(x) printf("debug:%s",x);
#define freep NULL;

const int INF = 0x3f3f3f3f;
const int MIN = 5;						//定义碎片最小容量

typedef unsigned int Uint;

//空闲区链表
typedef struct node 
	Uint size;							//空区大小(以字节计),包括区头所占空间
	struct node* next;					//后一分区地址
	struct node* back;					//前一分区地址
	Uint address;						//本分区首地址
freePartition,*pFreePartition;

//作业分配表
typedef struct table 
	int name;							//用户作业名
	Uint length;						//作业区大小
	int addr;							//作业区首地址
	bool flag;							//标记内存的状态,flag=true为占用
memTable;

pFreePartition head;					//空闲区表头
memTable tab[100];						//作业分配表,最多支持100个作业

void init() 
	//初始化空闲分区表
	int size;
	head = (pFreePartition)malloc(sizeof(freePartition));
	printf("请输入总分区大小:");
	scanf("%d", &size);

	assert(size > 5);											//判断总分区的合理性

	head->next = freep;											
	head->address = 0;
	head->back = freep;
	head->size = size;

	for (int i = 0; i < 100; i++) 
		tab[i].addr = INF;
		tab[i].flag = false;
	
	return ;


void addTable(int name, int size,int addr) 
	//往任务分配表中添加新任务
	for (int i = 0; i < 100; i++) 
		if (tab[i].flag == false) 
			tab[i].name = name;
			tab[i].addr = addr;
			tab[i].length = size;
			tab[i].flag = true;								//该内存块被占用
			return;
		
	


bool cmp(memTable a, memTable b) 
	return a.addr < b.addr;


void alterTable() 
	//修改任务分配表
	std::sort(tab, tab + 100, cmp);									//将任务分配表按从大到小的顺序排序
	tab[0].addr = 0;
	for (int i = 1; i < 100; i++) 
		if (!tab[i].flag) break;
		tab[i].addr = tab[i - 1].addr + tab[i - 1].length;		//更改任务起始地址
	


void compactMem(pFreePartition p) 
	//递归将p空闲分区合并到p.next中
	if (p == NULL) 
		return;
	
	if (p->next == NULL) 
		head = p;
		p->back = NULL;
		return;
	
	p->next->size += p->size;										//更改空闲分区的大小
	p->next->address -= p->size;									//更改空闲分区的地址
	compactMem(p->next);
	free(p);


void ffcolection() 
	//模拟分配内存模块
	int size;
	int name;
	bool flag = false;												//用于标识分配了一个完整的分区
	printf("\\n----------模拟分配作业内存模块----------\\n\\n");
	printf("\\n请输入需要分配的作业名:\\n");
	scanf("%d", &name);
	printf("\\n请输入需要分配的内存大小(单位 B):\\n");
	scanf("%d", &size);

	pFreePartition p = head;										//设置指针遍历空闲分区链表

	while (p != NULL) 
		if (p->size > size) 
			//当前内存区满足分配条件
			if (p->size - size > MIN) 
				//分配内存以后的空间满足内存碎片
				addTable(name, size, p->address);					//修改作业分配表
				p->size = p->size - size;							//修改空闲区链表
				p->address += size;
			
			else 
				//分配内存以后的空间不满足内存碎片的条件,直接分配给原进程
				addTable(name, p->size, p->address);
				flag = true;
				if (p == head) 
					//头结点为分区
					head = p->next;									//空闲区链表为空
					free(p);
					p = NULL;
				
				else 
					//非头结点为分区
					p->back->next = p->next;
					free(p);
					p = NULL;
				
			
			break;
		
		//当前内存区不满足内存分配条件
		p = p->next;
	

	if (p == NULL && flag == false) 
		//p==NULL有可能分配了一个完整的分区,有可能没有找到一个分区,flag==fasle标识没有找到一个完整的分区
		//尝试主存紧凑
		//printf("test1:%d\\n", head->address);
		compactMem(head);
		//printf("test2:%d\\n", head->address);
		//更改任务分配表
		alterTable();
		if (head==NULL||head->size < size) 
			printf("无法为任务提供足够内存!!\\n");
		
		else 
			addTable(name, size, head->address);
			head->size -= size;
			head->address += size;
			if (head->size == 0) 
				free(head);
				head = NULL;
			
		
	


void recolection() 
	//模拟释放内存模块
	int name;														//记录删除的进程名
	int address = ?存储管理

存储管理

操作系统-3.3-内存(动态分区分配算法&&基本分页存储管理详解)

计算机操作系统 存储器管理

操作系统——内存管理

物理内存管理