操作系統實驗報告——動態分區內存管理

操作系統實驗報告——動態分區內存管理

1、實驗名稱:動態分區內存分配算法的實現
2、實驗要求:
(1)理解動態分區管理方式的基本原理,
(2)掌握首次適應法、最佳適應法、最壞適應法三種分配 算法,
(3)用C或C++語言編程實現三種算法。
3、實驗方式: 通過實驗室的微機上機,實際調試程序。
4、實驗環境:

硬件環境:PC機一臺;
軟件環境:Windows10操作系統、C或C++程序設計語言。
5、實驗過程:
(1)算法描述:
1)根據當前算法在空閒分區鏈表中搜索合適空閒分區進行分配,分配時注意以下情況:
①找到可滿足空閒分區且分配後剩餘空間足夠大,則分割;
②找到可滿足空閒分區且但分配後剩餘空間比較小,則一起分配;
③找不可滿足需要的空閒分區但空閒分區之和能滿足需要,則採用內存緊縮技術,進行空閒分區的合併,然後再分配;
④在成功分配內存後,應保持空閒分區按照相應算法有序;
⑤分配成功則返回1,否則返回-1。
2)回收內存四種情況
①回收區與前一個空閒分區相鄰接,與前一分區合併,修改前一分區的大小;
②回收區與插入點的後一空閒分區相鄰接,將兩個分區合併,形成新的分區。(用回收區的首地址作爲新分區的首地址,大小爲其之和)
③回收區同時與前後兩個空閒分區相鄰接,合併三個分區,首地址爲第一個分區的首址,大小爲三個之和;
④回收區與之均不鄰接,建立新表項。
(2)實現代碼:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.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
/*描述每一個空閒塊的數據結構*/
struct free_block_type{
	int size;
	int start_addr;
	struct free_block_type *next;
};
/*每個進程分配到的內存塊的描述*/
struct allocated_block{
	int pid;
	int size;
	int start_addr;
	char process_name[PROCESS_NAME_LEN];
	struct allocated_block *next;
};
/*指向內存中空閒塊鏈表的首指針*/
struct free_block_type *free_block;
/*進程分配內存塊鏈表的首指針*/
struct allocated_block *allocated_block_head = NULL;
int mem_size=DEFAULT_MEM_SIZE; /*內存大小*/
int ma_algorithm = MA_FF;      /*當前分配算法*/
static int pid = 0;            /*初始pid*/
int flag = 0;                  /*設置內存大小標誌,防止重複設置*/
void display_menu();
void do_exit();
struct free_block_type *init_free_block(int mem_size);
void set_mem_size();
void set_algorithm();
void new_process();
void kill_process();
void display_mem_usage();
void rearrange(int choice);
void rearrage_FF();
void rearrage_BF();
void rearrage_WF();
main(){
    char choice;   
    pid=0;
    free_block = init_free_block(mem_size); //初始化空閒區
	display_menu();	
    while(1) {
    	printf("請選擇(0-5): ");
    	fflush(stdin);
    	choice=getchar();	//獲取用戶輸入
    	switch(choice){
     		case '1': 
			  set_mem_size(); //設置內存大小
			  system("cls");
			  break; 	
     		case '2': 
			  set_algorithm();//設置算法
			  flag=1;
			  system("cls");
			  break;
      		case '3':
			  new_process();//創建新進程
			  flag=1; 
			  system("cls");	 
			  break;
       		case '4':
			  kill_process();//刪除進程
		  	flag=1;  
		 	system("cls"); 
		  	break;
        	case '5':
		  		display_mem_usage();//顯示內存使用
	        	  flag=1; 
			  break;	
      	  case '0':
			  do_exit();//釋放鏈表並退出
			  exit(0);	
      		  default: break;   
  		 }  
   choice=getchar();
  } 
}
//緊縮處理
void free_memory_rearrage(int memory_reduce_size,int allocated_size){
	struct free_block_type *p1,*p2;
	struct allocated_block *a1,*a2;
	if(memory_reduce_size!=0) //分配完還有小塊空間
	{
		p1=free_block;
		p2=p1->next;
		p1->start_addr=0;
		p1->size=memory_reduce_size;
		p1->next=NULL;
		mem_size=memory_reduce_size;  //
	}
	else{
		p2=free_block;
		free_block=NULL;
		mem_size=0;
	}
	while(p2!=NULL)//釋放節點
	{
		p1=p2;
		p2=p2->next;
		free(p1);
	}
        //allocated_block 重新修改鏈接
		a1=(struct allocated_block *)malloc(sizeof(struct allocated_block));
		a1->pid=pid;
		a1->size=allocated_size;
		a1->start_addr=memory_reduce_size; //已申請的開始地址,從memory_reduce_size開始
		sprintf(a1->process_name, "PROCESS-%02d", pid);
		a1->next=allocated_block_head;
		a2=allocated_block_head;
		allocated_block_head=a1;
	while(a2!=NULL){
		a2->start_addr=a1->start_addr+a1->size;
		a1=a2;
		a2=a2->next;
	}
}
int allocate_mem(struct allocated_block *ab){
	//根據當前算法在空閒分區鏈表中搜索合適空閒分區進行分配,分配時注意以下情況:
	// 1. 找到可滿足空閒分區且分配後剩餘空間足夠大,則分割
	// 2. 找到可滿足空閒分區且但分配後剩餘空間比較小,則一起分配
	// 3. 找不可滿足需要的空閒分區但空閒分區之和能滿足需要,則採用內存緊縮技術,進行空閒分區的合併,然後再分配
	// 4. 在成功分配內存後,應保持空閒分區按照相應算法有序
	// 5. 分配成功則返回1,否則返回-1
	struct free_block_type *fbt, *pre;
	int request_size=ab->size;
 	//int memory_count;//計算剩餘分區總內存大小
	fbt = pre = free_block;
	while((pre!=NULL)&&(request_size>pre->size))//遍歷查找匹配空白區
	{
		//memory_count+=pre->size;
		fbt=pre;
		pre=pre->next;   
	}
	if(!pre)  //pre=pre->next結尾
	{
		if(mem_size>=request_size)/*memory_count*/
		{
			if(mem_size>=request_size+MIN_SLICE)
				free_memory_rearrage(mem_size-request_size,request_size); //採用緊縮技術
			else	
				free_memory_rearrage(0,mem_size); //採用緊縮技術,空間全部分配
			return 0;//全部重定位,不返回上級
		}
		else
			return -1;//分配失敗!
	}
	else  //內存能滿足 request_size<=pre->size
	{
		if((pre->size-request_size)>MIN_SLICE)//找到可滿足空閒分區且分配後剩餘空間足夠大,則分割
		{
		pre->size=pre->size-request_size;
		ab->start_addr=pre->start_addr+pre->size;
		}
		else//找到可滿足空閒分區且但分配後剩餘空間比較小,則一起分配,刪除該節點
		{
			if(pre==fbt){	
				fbt=pre->next;
				free_block=fbt;
			}
			else
				fbt->next=pre->next;
			ab->start_addr=pre->start_addr;
			ab->size=pre->size;
			free(pre);//釋放節點
			}
	}
	mem_size-=ab->size;//...
	rearrange(ma_algorithm);//分配成功,按照相應算法排序
    return 1;
}
void new_process(){
	struct allocated_block *ab;
	int size;
	int ret;/*ret==1表示從空閒分區分配空間成功*/
	if(mem_size==0){
		printf("內存全部分配!無法創建新進程,請先釋放其他進程!\n");
		return;
	}
	ab=(struct allocated_block *)malloc(sizeof(struct allocated_block));
	if(ab==NULL){
		printf("No Mem!\n");
		exit(1);
	}
	ab->next=NULL;
	pid++;
	sprintf(ab->process_name,"PROCESS-%02d",pid);//字符串格式化
	ab->pid=pid;
	while(1){
		printf("請輸入內存 %s(0-%d):",ab->process_name,mem_size);
		scanf("%d",&size);
		if(size<=mem_size&&size>0){
			ab->size=size;
			break;	
		}
		printf("請重新輸入!\n");
	}
	ret=allocate_mem(ab);//從空閒內存分配空間
        /*如果此時allocated_block_head尚未賦值,則賦值*/
        if((ret==1) &&(allocated_block_head == NULL))
	allocated_block_head=ab;
  	else if(ret==1) /*分配成功,將該已分配塊的描述插入已分配鏈表(頭插<無頭節點>)*/
	{
        ab->next=allocated_block_head;
        allocated_block_head=ab;
	}
	else if(ret==-1)/*分配不成功*/
	{ 
        printf("分配失敗!\n");
        free(ab);    
	return;
     	}
	printf("分配成功!\n");
}
struct allocated_block *find_process(int pid){
	struct allocated_block *p;
	p=allocated_block_head;
	while(p){
	if(p->pid==pid)
		return p;
	p=p->next;
	}
	return p;
}
/*釋放ab所表示的分配區*/
int free_mem(struct allocated_block *ab){ 
	int algorithm = ma_algorithm;
	struct free_block_type *fbt,*pre,*work;
	mem_size+=ab->size;
	fbt=(struct free_block_type *)malloc(sizeof(struct free_block_type));
	if(!fbt)
		return -1;
	fbt->size = ab->size;
	fbt->start_addr=ab->start_addr;
	fbt->next=NULL;
	rearrange(MA_FF);//按地址有序排列
	// 進行可能的合併,基本策略如下
	// 1. 將新釋放的結點插入到空閒分區隊列末尾
	// 2. 對空閒鏈表按照地址有序排列
	// 3. 檢查併合並相鄰的空閒分區
	// 4. 將空閒鏈表重新按照當前算法排序
	pre=NULL;
	work=free_block;
	//查找插入位置
	while((work!=NULL)&&(fbt->start_addr>work->start_addr)){
	pre=work;
	work=work->next;
	}
 	//插入當前節點
	//回收內存四種情況
		//1)回收區與前一個空閒分區相鄰接,與前一分區合併,修改前一分區的大小
		//2)回收區與插入點的後一空閒分區相鄰接,將兩個分區合併,形成新的分區。(用回收區的首地址作爲新分區的首地址,大小爲其之和)
		//3)回收區同時與前後兩個空閒分區相鄰接,合併三個分區,首地址爲第一個分區的首址,大小爲三個之和
		//4)回收區與之均不鄰接,建立新表項
	if(!pre)//插入開始位置
	{
		if (!work){
			 free_block=fbt; 
		}else{
			fbt->next=work;
		    free_block=fbt;
			if(fbt->start_addr+fbt->size==work->start_addr){	
				fbt->next=work->next;
				fbt->size=fbt->size+work->size;
				free(work);
			}
		}
	}
	else{
		if(!work){
			pre->next=fbt;
			if(fbt->start_addr==pre->start_addr+pre->size){
				pre->next=work;
				pre->size=fbt->size+pre->size;
				free(fbt);
			}
		}
		else{
			fbt->next=work;
			pre->next=fbt;
		// 檢查併合並相鄰的空閒分區
			if((fbt->start_addr== pre->start_addr+pre->size)&&(fbt->start_addr+fbt->size == work->start_addr)){
				pre->next=work->next;
				pre->size=pre->size+fbt->size+work->size;
				free(fbt);
				free(work);
			}
			else if(fbt->start_addr== pre->start_addr+pre->size){
				pre->next=work;
				pre->size=pre->size+fbt->size;
				free(fbt);
			}
			else if(work->start_addr==fbt->start_addr+fbt->size) {
				fbt->next=work->next;
				fbt->size=work->size+fbt->size;
				free(work);
			}
		}
	}
	// 將空閒鏈表重新按照當前算法排序
	rearrange(ma_algorithm);  
	return 1;
}
/*釋放ab數據結構節點*/
void dispose(struct allocated_block *free_ab){
	struct allocated_block *pre,*ab;
	if(free_ab==allocated_block_head)/*如果要釋放第一個節點*/
	{
		allocated_block_head=free_ab->next;
		free(free_ab);
		return ;
	}
	pre=allocated_block_head;
	ab=allocated_block_head->next;
	while(ab!=free_ab){
		pre=ab;
		ab=ab->next;
	}
	pre->next=ab->next;
	free(ab);
}
void kill_process(){
	struct allocated_block *ab;
	int pid;
	printf("終止進程,輸入序號 = ");
	scanf("%d",&pid);
	ab=find_process(pid);
	if(ab!=NULL){
	free_mem(ab);/*釋放ab所表示的分配區*/
	dispose(ab);/*釋放ab數據結構節點*/	
	printf("終止進程成功!\n");
	return;
	}
	printf("終止進程失敗!\n");
}
/* 顯示當前內存的使用情況,包括空閒區的情況和已經分配的情況 */
void display_mem_usage(){
	struct free_block_type *fbt=free_block;
	struct allocated_block *ab=allocated_block_head;
	/* 顯示空閒區 */
	printf("----------------------------------------------------------\n");
	if(fbt==NULL)
	printf("內存全部分配!\n");
	else{
	printf("空閒存儲器:\n");
	printf("%20s %20s\n", "起始地址", "大小");
	while(fbt!=NULL){
	printf("%17d %23d\n", fbt->start_addr, fbt->size);
        fbt=fbt->next;
	}
	}	printf("----------------------------------------------------------\n");
	/* 顯示已分配區 */
	if(ab==NULL)
	printf("尚未開始分配!\n");
	else{
	printf("\nUsed Memory:\n");
	printf("%10s %15s %15s %10s\n", "\t序號", "進程名稱", "起始地址", "大小");
    	while(ab!=NULL){
        printf("%10d %18s %12d %11d\n", ab->pid, ab->process_name, ab->start_addr, ab->size);
        ab=ab->next;
        }
	}
	printf("----------------------------------------------------------\n");
}
/*按BF算法重新整理內存空閒塊鏈表*/
void rearrage_BF(){
	struct free_block_type *p,*p1,*p2;
	struct free_block_type *last_flag;
	p1=(struct free_block_type *)malloc(sizeof(struct free_block_type));
	p1->next=free_block;
    free_block=p1;//不改變p1,free_block指向頭p1
	if(free_block!=NULL){
		for (last_flag=NULL; last_flag!=free_block; last_flag=p){
			for (p=p1=free_block; p1->next!=NULL&&p1->next->next!=NULL&&p1->next->next!=last_flag; p1=p1->next){
			   if (p1->next->size > p1->next->next->size){
				p2 = p1->next->next;  
				p1->next->next = p2->next;
				p2->next = p1->next; 
				p1->next = p2; 
				p = p1->next->next; 
			   }
			}
		}	
	}
	p1 = free_block; 
	free_block = free_block->next; 
	free(p1); 
	p1 = NULL; 
}
/*按WF算法重新整理內存空閒塊鏈表*/
void rearrage_WF(){
	struct free_block_type *p,*p1,*p2;
	struct free_block_type *last_flag;
	p1=(struct free_block_type *)malloc(sizeof(struct free_block_type));
	p1->next=free_block;
    free_block=p1;//不改變p1,free_block指向頭p1
	if(free_block!=NULL){
		for (last_flag=NULL; last_flag!=free_block; last_flag=p){
		for (p=p1=free_block; p1->next!=NULL&&p1->next->next!=NULL&&p1->next->next!=last_flag; p1=p1->next){
		   if (p1->next->size < p1->next->next->size) {
			p2 = p1->next->next;  
			p1->next->next = p2->next; 
			p2->next = p1->next; 
			p1->next = p2; 
			p = p1->next->next; 
		   }
		}
	}
	}
	p1 = free_block; 
	free_block = free_block->next; 
	free(p1); 
	p1 = NULL; 
}
void rearrage_FF(){
	struct free_block_type *p,*p1,*p2;
	struct free_block_type *last_flag;
	p1=(struct free_block_type *)malloc(sizeof(struct free_block_type));
	p1->next=free_block;
    free_block=p1;//不改變p1,free_block指向頭p1
	if(free_block!=NULL){
		for (last_flag=NULL; last_flag!=free_block; last_flag=p){
			for (p=p1=free_block;p1->next!=NULL&&p1->next->next!=NULL &&p1->next->next!=last_flag; p1=p1->next){
			   if (p1->next->start_addr > p1->next->next->start_addr) {
				p2 = p1->next->next;  
				p1->next->next = p2->next; 
				p2->next = p1->next; 
				p1->next = p2; 
				p = p1->next->next; 
			   }
			}
		}
	}
	p1 = free_block; 
	free_block = free_block->next; 
	free(p1); 
	p1 = 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");
		exit(1);
	}
	fb->size=mem_size;
	fb->start_addr=DEFAULT_MEM_START;
	fb->next=NULL;
	return fb;
}
void display_menu(){
    printf("\n");
	printf("----------------------------------------------------------\n");
	printf("                    存儲器管理實驗 \n");
    printf("1 - 設置內存大小 (default=%d)\n", DEFAULT_MEM_SIZE);
    printf("2 - 選擇內存分配算法\n");
    printf("3 - 創建進程 \n"); 
    printf("4 - 終止進程 \n");
    printf("5 - 顯示內存使用情況 \n");
    printf("0 - 退出\n");
	printf("----------------------------------------------------------\n");
}
void rearrange(int choice){
	switch(choice){
	case 1:rearrage_FF();
	       break;
	case 2:rearrage_BF();
	       break;
	case 3:rearrage_WF();
		   break;
	}
}
void set_algorithm(){
    int algorithm;
    printf("\t1 - 首次適應算法\n");
    printf("\t2 - 最佳適應算法 \n");
    printf("\t3 - 最差適應算法 \n");
    scanf("%d", &algorithm);
    if(algorithm>=1 && algorithm <=3)  
		ma_algorithm=algorithm;
    rearrange(ma_algorithm); //按指定算法重新排列空閒區鏈表
}
void set_mem_size(){
    int size;
    if(flag!=0){  
        printf("無法再次設置內存大小,或您已經開始使用內存!\n");
	return;
    }
    printf("總內存大小 =");
    scanf("%d", &size);
    if(size>0){
        mem_size = size;
        free_block->size = mem_size;
    }
    flag=1;  
}
void do_exit(){
	struct free_block_type *p1,*p2;
	struct allocated_block *a1,*a2;
	p1=free_block;
	if(p1!=NULL){
	p2=p1->next;
	for(;p2!=NULL;p1=p2,p2=p2->next){
		free(p1);
	}
	free(p1);
	}
	a1=allocated_block_head;
	if(a1!=NULL){
		a2=a1->next;
		for(;a2!=NULL;a1=a2,a2=a2->next){
			free(a1);	
		}
		free(a1);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章