Linux内存分配--实现FF、BF、WF分配算法

v 通过深入理解内存分配管理的三种算法,定义相应的数据结构,编写具体代码。 充分模拟三种算法的实现过程,并通过对比,分析三种算法的优劣。
v 1 )掌握内存分配 FF BF WF 策略及实现的思路;
v 2 )掌握内存回收过程及实现思路;
v 3 )参考给出的代码思路,实现内存的申请、释放的管理程序,调试运行,总结程序设计中出现的问题并找出原因,写出实验报告。

首次适应(first-fit):将空闲内存链表按开始地址从小到大排序,从链表头开始查找(也可以从上次查找结束位置),分配首个足够大的孔。

最优适应(best-fit):将空闲内存链表按大小从小到大排序,从链表头开始查找,分配首个足够大的孔。

最差适应(worst-fit):将空闲内存链表按大小从大到小排序,从链表头开始查找,分配首个足够大的孔。

内存申请原则:

     1. 找到可满足空闲分区且分配后剩余空间足够大(大于最小碎片),则分割

     2. 找到可满足空闲分区且但分配后剩余空间比较小(小于最小碎片),则一起分配

     3. 找不可满足需要的空闲分区但空闲分区之和能满足需要,则采用内存紧缩技术,进行空闲分区的合并,然后再分配

     4. 在成功分配内存后,应保持空闲分区按照相应算法有序

         内存释放原则:

             1. 将新释放的结点插入到空闲分区队列末尾

             2. 对空闲链表按照地址有序排列

             3. 检查并合并相邻的空闲分区

             4. 将空闲链表重新按照当前算法排序

代码实现:

#include<unistd.h>
#include<stdio.h>  
#include<stdlib.h> 
#include<stddef.h>

#define PROCESS_NAME_LEN 32   		/*进程名长度*/
#define MIN_SLICE    10             /*最小碎片的大小*/
#define DEFAULT_MEM_SIZE 1024    	/*内存大小*/
#define DEFAULT_MEM_START 0       	/*起始位置*/
/* 内存分配算法 */
#define MA_FF 1
#define MA_BF 2
#define MA_WF 3
int mem_size=DEFAULT_MEM_SIZE; 		/*内存大小*/
int ma_algorithm = MA_FF;           /*当前分配算法*/
static int pid = 0;                 /*初始pid*/
int flag = 0;                       /*设置内存大小标志*/
/*描述每一个空闲块的数据结构*/
struct free_block_type{
	int size;
	int start_addr;
	struct free_block_type *next;
};  

/*指向内存中空闲块链表的首指针*/
struct free_block_type *free_block;

/*每个进程分配到的内存块的描述*/
struct allocated_block{
	int pid;    int size;
	int start_addr;
	char process_name[PROCESS_NAME_LEN];
	struct allocated_block *next;
};
/*进程分配内存块链表的首指针*/
struct allocated_block *allocated_block_head = NULL;


/*初始化空闲块,默认为一块,可以指定大小及起始地址*/
struct free_block_type* init_free_block(int mem_size){
	struct free_block_type *fb;

	fb=(struct free_block_type *)malloc(sizeof(struct free_block_type));
	if(fb==NULL){
		printf("No mem\n");
		return NULL;
	}
	fb->size = mem_size;
	fb->start_addr = DEFAULT_MEM_START;
	fb->next = NULL;
	return fb;
}

/*显示菜单*/
void display_menu(){
	printf("\n");
	printf("1 - Set memory size (default=%d)\n", DEFAULT_MEM_SIZE);
	printf("2 - Select memory allocation algorithm\n");
	printf("3 - New process \n");
	printf("4 - Terminate a process \n");
	printf("5 - Display memory usage \n");
	printf("0 - Exit\n");
}

/*设置内存的大小*/
int set_mem_size(){
	int size;
	if(flag!=0){  //防止重复设置
		printf("Cannot set memory size again\n");
		return 0;
	}
	printf("Total memory size =");
	scanf("%d", &size);
	if(size>0) {
		mem_size = size;
		free_block->size = mem_size;
	}
	flag=1;  return 1;
}

/*按FF算法重新整理内存空闲块链表*/
void rearrange_FF(){   
	struct free_block_type *head = free_block;
	int free_block_count = 0;	//计算节点数
	while(head != NULL) {
		free_block_count++;
		head = head->next;
	}
	int i = 0,j = 0;
	/*冒泡排序*/
	for (i;i < free_block_count - 1;i++){
		struct free_block_type *node = free_block;
		struct free_block_type *pre = free_block;
		j = 0;
		for (j;j < free_block_count - 1 - i;j++){
			if(node->start_addr > node->next->start_addr){ //如果前驱节点地址大于后续节点
				if(j == 0){
					free_block = node->next;	//如果是前两个交换,注意更换free_block的指向
					struct free_block_type *temp = node->next;
					node->next = temp->next;
					temp->next = node;
				}else{
					struct free_block_type *temp = node->next;
					pre->next = temp;
					node->next = temp->next;
					temp->next = node;
				}
			}else{
				pre = node;
				node = node->next;
			}
		}
	}
}
/*按BF算法重新整理内存空闲块链表*/
void rearrange_BF(){
	struct free_block_type *head = free_block;
	int free_block_count = 0;	//计算节点数
	while(head != NULL) {
		free_block_count++;
		head = head->next;
	}
	int i = 0,j = 0;
	/*冒泡排序*/
	for (i;i < free_block_count - 1;i++){
		struct free_block_type *node = free_block;
		struct free_block_type *pre = free_block;
		j = 0;
		for (j;j < free_block_count - 1 - i;j++){
			if(node->size > node->next->size){ //如果前驱节点size大于后续节点
				if(j == 0){
					free_block = node->next;	//如果是前两个交换,注意更换free_block的指向
					struct free_block_type *temp = node->next;
					node->next = temp->next;
					temp->next = node;
				}else{
					struct free_block_type *temp = node->next;
					pre->next = temp;
					node->next = temp->next;
					temp->next = node;
				}
			}else{
				pre = node;
				node = node->next;
			}
		}
	}
}
/*按WF算法重新整理内存空闲块链表*/
void rearrange_WF(){
	struct free_block_type *head = free_block;
	int free_block_count = 0;	//计算节点数
	while(head != NULL) {
		free_block_count++;
		head = head->next;
	}
	int i = 0,j = 0;
	/*冒泡排序*/
	for (i;i < free_block_count - 1;i++){
		struct free_block_type *node = free_block;
		struct free_block_type *pre = free_block;
		j = 0;
		for (j;j < free_block_count - 1 - i;j++){
			if(node->size < node->next->size){ //如果前驱节点size小于后续节点
				if(j == 0){
					free_block = node->next;  //如果是前两个交换,注意更换free_block的指向
					struct free_block_type *temp = node->next;
					node->next = temp->next;
					temp->next = node;
				}else{
					struct free_block_type *temp = node->next;
					pre->next = temp;
					node->next = temp->next;
					temp->next = node;
				}
			}else{
				pre = node;
				node = node->next;
			}
		}
	}
}

/*按指定的算法整理内存空闲块链表*/
void rearrange(int algorithm){
	switch(algorithm){
		case MA_FF:  rearrange_FF(); break;
		case MA_BF:  rearrange_BF(); break;
		case MA_WF:  rearrange_WF(); break;
	}
}

/* 设置当前的分配算法 */
void set_algorithm(){
	int algorithm;
	printf("\t1 - First Fit\n");
	printf("\t2 - Best Fit \n");
	printf("\t3 - Worst Fit \n");
	scanf("%d", &algorithm);
	if(algorithm>=1 && algorithm <=3)  
		ma_algorithm=algorithm;
	//按指定算法重新排列空闲区链表
	rearrange(ma_algorithm); 
}

/*创建新的进程,主要是获取内存的申请数量*/
int new_process(){
	struct allocated_block *ab;
	int size;    int ret;
	ab=(struct allocated_block *)malloc(sizeof(struct allocated_block));
	if(!ab) exit(-5);
	ab->next = NULL;
	pid++;
	sprintf(ab->process_name, "PROCESS-%02d", pid);
	ab->pid = pid;    
	printf("Memory for %s:", ab->process_name);
	scanf("%d", &size);
	if(size>0) ab->size=size;
	ret = allocate_mem(ab);  /* 从空闲区分配内存,ret==1表示分配ok*/
	/*如果此时allocated_block_head尚未赋值,则赋值*/
	if((ret==1) &&(allocated_block_head == NULL)){ 
		allocated_block_head=ab;
		ab->next = NULL;
		return 1;        
	}
	/*分配成功,将该已分配块的描述插入已分配链表*/
	else if (ret==1) {
		ab->next=allocated_block_head;
		allocated_block_head=ab;
		return 2; 
	}
	else if(ret==-1){ /*分配不成功*/
		printf("Allocation fail\n");
		free(ab);
		return -1;       
	}
	return 3;
}
/*内存紧缩操作*/
void mem_compact(int sliceSize){	//参数为所有空闲内存大小
	struct allocated_block *ab = allocated_block_head;
	free_block->start_addr = 0;
	free_block->size = sliceSize;
	free_block->next = NULL;		//紧缩原则是空闲内存从地址0开始
	while(ab != NULL){
		ab->start_addr = sliceSize;
		sliceSize += ab->size;
		ab = ab->next;
	}
}
/*分配内存模块*/
int allocate_mem(struct allocated_block *ab){
	struct free_block_type *fbt, *pre;
	int request_size=ab->size;
	fbt = pre = free_block;
	int totalSize = 0;
	if(fbt == NULL) return -1;  	//如果空闲内存为空,则分配失败
	while (fbt != NULL){
		totalSize += fbt->size;		//计算所有孔大小
		if (fbt->size >= request_size){		//如果找到大小足够的孔,分两种情况
			if(fbt->size - request_size >= MIN_SLICE){		//1.孔足够大,无内部碎片,重新分割。空闲孔顺序不变。
				ab->start_addr = fbt->start_addr;
				fbt->start_addr = fbt->start_addr + request_size;
				fbt->size = fbt->size - request_size;
			}else{									//2.孔不够大,产生内部碎片,直接分配。空闲孔顺序改变。
				ab->size = fbt->size;
				ab->start_addr = fbt->start_addr;
				if (fbt == free_block) free_block = fbt->next;
				else pre->next = fbt->next;				//删除目前空闲孔
			}
			return 1;
		}else{						//目前孔不够大,则查找后续空闲孔
			pre = fbt;
			fbt = fbt->next;
		}
	}
	//单个孔无法满足需求,考虑内存紧缩
	if (totalSize >= request_size){			//所有孔大小和大于需求,可以进行紧缩
		mem_compact(totalSize);				//紧缩操作
		if(totalSize - request_size >= MIN_SLICE){ 		//1.孔足够大,无内部碎片,重新分割。空闲孔顺序不变。
			free_block->size = free_block->size - request_size;
			ab->start_addr = free_block->size;
		}else{								//2.孔不够大,产生内部碎片,直接分配。空闲孔顺序改变。
			free_block->size = 0;
			free_block = NULL;
			ab->start_addr = free_block->start_addr;
		}
		return 1;
	}else return -1;	//无法紧缩,分配失败。

}

/*找到id为pid的进程并返回*/
struct allocated_block* find_process(int pid){
	struct allocated_block *ab;
	ab = allocated_block_head;
	while(ab != NULL){
		if (ab->pid == pid) return ab;
		ab = ab->next;
	}
	printf("can't find process %d",pid);
	return NULL;
}

/*删除进程,归还分配的存储空间,并删除描述该进程内存分配的节点*/
void kill_process(){
	struct allocated_block *ab;
	int pid;
	printf("Kill Process, pid=");
	scanf("%d", &pid);
	ab=find_process(pid);
	if(ab!=NULL){
		free_mem(ab); /*释放ab所表示的分配区*/
		dispose(ab);  /*释放ab数据结构节点*/
	}
}

/*将ab所表示的已分配区归还,并进行可能的合并*/
int free_mem(struct allocated_block *ab){
	int algorithm = ma_algorithm;
	struct free_block_type *fbt, *pre, *work;
	fbt=(struct free_block_type*) malloc(sizeof(struct free_block_type));
	pre=(struct free_block_type*) malloc(sizeof(struct free_block_type));
	if(!fbt) return -1;
	fbt->size = ab->size;
	fbt->start_addr = ab->start_addr;
	//1.插到队尾
	work = free_block;		
	if(work == NULL){
		free_block = work;
		work->next = NULL;
	}else{
		while(work->next != NULL) work = work->next;
		work->next = fbt;
		fbt->next = NULL;
	}
	//2.按地址有序排列
	rearrange_FF();
	//3.合并相邻空闲分区
	pre = free_block;
	if(pre != NULL){
		work = pre->next;
		while(work != NULL){
			work = pre->next;
			if(pre->start_addr + pre->size == work->start_addr) {
				pre->next = work->next;
				pre->size += work->size;
				free(work);
			}else pre = pre->next;
			if(pre != NULL) work = pre->next;
			else work = NULL;
		}
	}
	//按当前算法重新排序
	rearrange(algorithm);
	// 进行可能的合并,基本策略如下
	// 1. 将新释放的结点插入到空闲分区队列末尾
	// 2. 对空闲链表按照地址有序排列
	// 3. 检查并合并相邻的空闲分区
	// 4. 将空闲链表重新按照当前算法排序
	return 1;
}

/*释放ab数据结构节点*/
int dispose(struct allocated_block *free_ab){
	struct allocated_block *pre, *ab;
	if(free_ab == allocated_block_head) { /*如果要释放第一个节点*/
		allocated_block_head = allocated_block_head->next;
		free(free_ab);
		return 1;
	}
	pre = allocated_block_head;  
	ab = allocated_block_head->next;
	while(ab!=free_ab){ pre = ab;  ab = ab->next; }
	pre->next = ab->next;
	free(ab);
	return 2;
}
/* 显示当前内存的使用情况,包括空闲区的情况和已经分配的情况 */
int display_mem_usage(){
	struct free_block_type *fbt=free_block;
	struct allocated_block *ab=allocated_block_head;
	if(fbt==NULL) return(-1);
	printf("----------------------------------------------------------\n");
	/* 显示空闲区 */
	printf("Free Memory:\n");
	printf("%20s %20s\n", "      start_addr", "       size");
	while(fbt!=NULL){
		printf("%20d %20d\n", fbt->start_addr, fbt->size);
		fbt=fbt->next;
	}
	/* 显示已分配区 */
	printf("\nUsed Memory:\n");
	printf("%10s %20s %10s %10s\n", "PID", "ProcessName", "start_addr", " size");
	while(ab!=NULL){
		printf("%10d %20s %10d %10d\n", ab->pid, ab->process_name, ab->start_addr, ab->size);
		ab=ab->next;
	}
	printf("----------------------------------------------------------\n");
	return 0;
}

int main(){
	char choice;      pid=0;
	free_block = init_free_block(mem_size); //初始化空闲区
	while(1) {
		display_menu();		//显示菜单
		fflush(stdin);
		choice=getchar();	//获取用户输入
		switch(choice){
			case '1': set_mem_size(); break; 	//设置内存大小
			case '2': set_algorithm();flag=1; break;//设置算法
			case '3': new_process(); flag=1; break;//创建新进程
			case '4': kill_process(); flag=1;   break;//删除进程
			case '5': display_mem_usage();    flag=1; break;	//显示内存使用
			case '0': exit(0);	//释放链表并退出
			default: break;      
		}
		while(1){
			if(getchar() == '\n') break;
		}
	} 
	return 0;
}

参考资料:《操作系统概念(第九版)》

二、内存管理与多进程(含源码)_稳健的不高冷的强哥的博客-CSDN博客

内存分配---FF、BF、WF三种算法_weixin_30878501的博客-CSDN博客

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值