- 姓名:倪曉東
- 學號:201821121020
- 班級: 計算1811
1. 記錄內存空間使用情況
解釋你是如何記錄內存空間使用情況,給出關鍵代碼。
/*記錄內存空間使用情況,每個進程分配到的內存塊描述*/ struct allocated_block { int pid; int size; //進程大小 int start_addr; //進程分配到的內存塊的起始地址 char process_name[PROCESS_NAME_LEN]; //進程名 struct allocated_block *next; //指向下一個進程控制塊 };
2. 記錄空閑分區
用什么樣的方法記錄內存空閑區,給出關鍵代碼。
//空閑分區,描述每一個空閑塊的數據結構 struct free_block_type { int size; //空閑塊大小 int start_addr; //空閑塊起始位置 struct free_block_type *next; //指向下一個空閑塊 };
//指向內存中空閑塊鏈表的首地址 struct free_block_type *free_block= NULL;
空閑分區鏈表:
//按首次適配算法重新整理內存空閑塊鏈表,按空閑塊首地址排序 int rearrange_FF() { struct free_block_type *head= free_block; struct free_block_type *forehand,*pre,*rear; int i; if(head== NULL) return -1; for(i= 0;i< free_block_count-1;i++) { forehand= head; pre= forehand->next; rear= pre->next; while(pre->next!= NULL) { if(forehand== head&&forehand->start_addr>= pre->start_addr) { //比較空閑鏈表中第一個空閑塊與第二個空閑塊的開始地址的大小 head->next= pre->next; pre->next= head; head= pre; forehand= head->next; pre= forehand->next; rear= pre->next; } else if(pre->start_addr>= rear->start_addr) { //比較鏈表中其它相鄰兩個結點的開始地址的大小 pre->next= rear->next; forehand->next= rear; rear->next= pre; forehand= rear; rear= pre->next; } else { forehand= pre; pre= rear; rear= rear->next; } } } return 0; }
3. 內存分配算法
使用首次適配算法內存分配:
//按照首次適應算法給新進程分配內存空間 int allocate_FF(struct allocated_block *ab) { int ret; struct free_block_type *pre= NULL,*ff= free_block; if(ff== NULL) return -1; while(ff!= NULL) { if(ff->size>= ab->size) { ret= allocate(pre,ff,ab); break; } pre= ff; pre= pre->next; } if(ff== NULL&¤t_free_mem_size> ab->size) ret= mem_retrench(ab); else ret= -2; rearrange_FF(); return ret; }
4. 內存釋放算法
int exit() { struct allocated_block *allocated_ab,*allocated_pre; struct free_block_type *free_ab,*free_pre; free_pre= free_block; allocated_pre= allocated_block_head; if(free_pre!= NULL) //鏈表不為空 { free_ab= free_pre->next; while(free_ab!= NULL) { free(free_pre); //釋放當前節點 free_pre= free_ab; free_ab= free_ab->next; //節點后移 } } if(allocated_pre!= NULL) { allocated_ab= allocated_pre->next; while(allocated_ab!= NULL) { free(allocated_pre); //釋放節點 allocated_pre= allocated_ab; allocated_ab= allocated_ab->next; //節點后移 } } allocated_ab= allocated_ab->next; return 0; }
刪除進程,歸還分配的存儲空間,並刪除描述該進程內存分配的結點
void kill_process() { struct allocated_block *ab; int pid; printf("Kill Process,pid=");//刪除進程號為 scanf("%d",&pid); getchar(); ab= find_process(pid); //找到pid對應的鏈表節點 if(ab!= NULL) { free_mem(ab); //釋放ab所表示的分配區 dispose(ab); //釋放ab數據結構結點 } }
在進程分配鏈表中尋找指定進程:
struct allocated_block* find_process(int pid) { struct allocated_block *ab= allocated_block_head; if(ab== NULL) { printf("不存在!\n"); return NULL; } while(ab->pid!= pid&&ab->next!= NULL)//查找整個鏈表 ab= ab->next; if(ab->next== NULL&&ab->pid!= pid)//找不到 { printf("error!\n"); return NULL; } return ab; }
5. 運行結果
(1)產生測試數據
設置內存大小為1000,每次為進程分配1-100內存大小:
設置內存大小為200,每次為進程分配1-20內存大小:
(2)解釋結果
內存總大小為200,每次為進程分配1-20內存
如圖所示,創建的第一個進程號PID=1,進程名稱為PEOCESSNAME-01,內存起始地址為0,內存大小為2,空閑區首地址為2,剩余內存198。
如圖所示,創建的第二個進程號PID=2,進程名稱為PEOCESS-02,內存起始地址為2,分配到的內存大小為8,空閑區首地址為10,剩余內存190。
如圖所示,創建的第二個進程號PID=3,進程名稱為PEOCESS-03,內存起始地址為10,分配到的內存大小為15,空閑區首地址為25,剩余內存175。
如圖所示,創建的第二個進程號PID=4,進程名稱為PEOCESS-04,內存起始地址為25,分配到的內存大小為1,空閑區首地址為26,剩余內存174。
小結:
首次適配算法從空閑區的第一個表目起查找該表,把最先能夠滿足要求的空閑區分配給進程,這種方法目的在於減少查找時間。為適應這種算法,空閑區鏈中的空閑分區要按地址由低到高進行排序。該算法優先使用低址部分空閑區,在低址空間造成許多小的空閑區,在高地址空間保留大的空閑區。但是在實際使用過程中,由於優先使用低址的可用空閑區,低址部分被不斷進行分配,但又不能保證剛好完全利用,所以會留下很多不能被使用小空閑區,而且每次為進程分配內存從低址開始尋找,就要和這些小空閑區適配,會影響速率。
參考文獻:https://github.com/City-Zero/LinuxTest/blob/master/OSex/mem_manager/mm.c