一、要求:html
用C語言分別實現採用首次適應算法和最佳適應算法的動態分區分配過程alloc()和回收過程free()。其中,空閒分區經過空閒分區鏈來管理:在進行內存分配時,系統優先使用空閒區低端的空間。ios
假設初始狀態下,可用的內存空間爲640KB,並有下列的請求序列: 算法
•做業1申請130KB •做業2申請60KB。 數據結構
•做業3申請100KB •做業2釋放60KB。 函數
•做業4申請200KB •做業3釋放100KB。spa
•做業1釋放130KB •做業5申請140KB。 指針
•做業6申請60KB •做業7申請50KB •做業6釋放60KB。調試
請分別採用首次適應算法和最佳適應算法,對內存塊進行分配和回收,要求每次分配和回收後顯示出空閒分區鏈的狀況。code
二、數據結構:htm
程序採用鏈式存儲結構存儲空閒分區鏈。首先定義空閒分區表的結構體,包括空閒分區表的id號,首地址、分區大小、分配標誌。而後用結構體表示鏈表的每個節點,包括分區表結構體、front和next指針。
三、最佳適應算法思路:
首先,定義一個p指針,讓p指針遍歷空閒分區鏈表,當找到第一個知足進程請求空間大小的空閒區時,記錄此位置,而且保存請求大小與空閒分區實際大小的差值記爲a,而後讓p指針繼續遍歷空閒分區鏈表,每當知足請求內存大小小於空閒區大小時,就記錄二者的差值而且記錄爲b,比較a與b的大小關係,當a>b時,將b的值賦予a,而且修改記錄位置爲此空閒區的位置。若,a<=b,不作操做。繼續遍歷鏈表,重複上面的操做,直到p->next指向null爲止。
四、 首次適應算法思路:
首次適應算法比較簡單,只要找到知足條件的空閒區,就將此區的空間分配給進程。首先,用P指針遍歷鏈表,找到第一個空間大於或者等於請求大小的位置,將此空間分配給進程,當此空閒區大小大於請求空間大小時,將空閒區分爲兩部分,一部分分配給進程,另外一部分爲空閒區,它的大小爲以前空閒區大小減去分配給進程的空間大小。
5:、內存回收算法思想:
內存回收時,回收分區與空閒分區有四種關係。第一種狀況爲回收分區r上臨一個空閒分區,此時應該合併爲一個連續的空閒區,其始址爲r上相鄰的分區的首地址,而大小爲二者大小之和。第二種狀況爲回收分區r與下相鄰空閒分區,合併後仍然爲空閒區,該空閒區的始址爲回收分區r的地址。大小爲二者之和,第三種狀況爲回收部分r與上下空閒區相鄰,此時將這三個區域合併,始址爲r上相鄰區域的地址,大小爲三個分區大小之和。當回收部分r上下區域都爲非空閒區域,此時創建一個新的空閒分區,而且加入到空閒區隊列中去。
六、主要函數僞代碼:
Void first_fit()//首次適應算法 { 定義一個臨時節點temp儲存進程ID,和請求內存大小size,標記爲繁忙BUSY; 定義p指針用來遍歷空閒區鏈表; 初始p指向鏈表頭結點; While(p) { if(p爲空閒區&&p大小恰好知足要求) { 將此區域分配給進程; 標記爲繁忙區域; Return 1; Break; } If(p爲空閒區&&空閒區大小比進程請求空間大小大) { 將temp插入到鏈表此位置上,而且將此位置的地址賦予Temp,剩餘空閒區的大小爲空閒區大小與請求空間之差; } P=p->next; } Return 1; }
Void best_fit()//最佳適應算法 { 定義surplus記錄可用內存與需求內存的差值; 定義一個臨時節點temp儲存進程ID,和請求內存大小size,標記爲繁忙BUSY; 定義p指針用來遍歷空閒區鏈表; 初始p指向鏈表頭結點; 定義q做爲標記節點; While(p) { If(p爲空閒區&&p知足內存大小大於進程請求大小) { Q=p; 將二者差值賦予surplus; Return 1; Break; } P=p->next; } While(p) { if(p爲空閒區&&p大小恰好知足要求) { 將此區域分配給進程; 標記爲繁忙區域; Break; } If(p爲空閒區&&空閒區大小比進程請求空間大小大) { If(surplus大於請求大小與內存空閒區大小之差) 更新surplus爲請求大小與內存空閒區大小之差; Q=p; } P=p->next; } If( q爲空) { Return 0; } Else(找到了最佳位置) { 將temp插入到鏈表此位置上,而且將此位置的地址賦予Temp,剩餘空閒區的大小爲空閒區大小與請求空間之差; Return 1; } }
Int free(int ID)//內存回收算法 { 定義p指針用來遍歷空閒區鏈表; While(p) { If(須要回收的ID等於p的ID) { 先釋放P指向的內存; If(p上相鄰區域爲空閒區&&p下相鄰區域爲繁忙區) { 將p與上相鄰區域合併; 此空閒區大小爲二者大小之和; 首地址爲p上相鄰區域地址; } If(p下相鄰區域爲空閒區&&p上相鄰區域爲繁忙區) { 將p與下相鄰區域合併; 此空閒區大小爲二者大小之和; 首地址爲p下相鄰區域地址; } If(p上相鄰區域爲空閒區&&p下相鄰區域爲空閒區) { 將p與上、下相鄰區域合併; 此空閒區大小爲三者大小之和; 首地址爲p上相鄰區域地址; } If(p上相鄰區域爲繁忙區&&p下相鄰區域爲繁忙區) { 新建空閒區; } Break; } p=p->next; } 輸出回收成功! Return 1; }
七、源代碼:
#include <iostream> using namespace std; #define FREE 0 #define BUSY 1 #define MAX_length 640 typedef struct freeArea//首先定義空閒區分表結構 { int flag; int size; int ID; int address; }Elemtype; typedef struct Free_Node { Elemtype date; struct Free_Node *front; struct Free_Node *next; }Free_Node,*FNodeList; FNodeList block_first; FNodeList block_last; int alloc(int tag);//內存分配 int free(int ID);//內存回收 int first_fit(int ID,int size);//首次適應算法 int best_fit(int ID,int size);//最佳適應算法 void show();//查看分配 void init();//初始化 void Destroy(Free_Node *p);//銷燬節點 void menu(); void init()// { block_first=new Free_Node; block_last = new Free_Node; block_first->front=NULL; block_first->next=block_last; block_last->front=block_first; block_last->next=NULL; block_last->date.address=0; block_last->date.flag=FREE; block_last->date.ID=FREE; block_last->date.size=MAX_length; } //實現內存分配 int alloc(int tag) { int ID,size1; cout<<"請輸入做業號:"; cin>>ID; cout<<"請輸入所需內存大小:"; cin>>size1; if (ID<=0 || size1<=0) { cout<<"ERROR,請輸入正確的ID和請求大小"<<endl; return 0; } if (tag==1)//採用首次適應算法 { if(first_fit(ID,size1)) { cout<<"分配成功!"<<endl; } else cout<<"分配失敗!"<<endl; return 1; } else { if (best_fit(ID,size1)) { cout<<"分配成功!"<<endl; } else cout<<"分配失敗!"<<endl; return 1; } } int first_fit(int ID,int size)//首次適應算法 { FNodeList temp=(FNodeList)malloc(sizeof(Free_Node)); Free_Node *p=block_first->next; temp->date.ID=ID; temp->date.size=size; temp->date.flag=BUSY; while(p) { if (p->date.flag==FREE && p->date.size==size)//請求大小恰好知足 { p->date.flag=BUSY; p->date.ID=ID; return 1; break; } if (p->date.flag==FREE && p->date.size>size)//說明還有其餘的空閒區間 { temp->next=p; temp->front=p->front; temp->date.address=p->date.address; p->front->next=temp; p->front=temp; p->date.address=temp->date.address+temp->date.size; p->date.size-=size; return 1; break; } p=p->next; } return 0; } int best_fit(int ID,int size)//最佳適應算法 { int surplus;//記錄可用內存與需求內存的差值 FNodeList temp=(FNodeList)malloc(sizeof(Free_Node)); Free_Node *p=block_first->next; temp->date.ID=ID; temp->date.size=size; temp->date.flag=BUSY; Free_Node *q=NULL;//記錄最佳位置 while(p)//遍歷鏈表,找到第一個可用的空閒區間將他給q { if (p->date.flag==FREE&&p->date.size>=size) { q=p; surplus=p->date.size-size; break; } p=p->next; } while(p)//繼續遍歷,找到更加合適的位置 { if (p->date.flag==FREE&&p->date.size==size) { p->date.flag=BUSY; p->date.ID=ID; return 1; break; } if (p->date.flag==FREE&&p->date.size>size) { if (surplus>p->date.size-size) { surplus=p->date.size-size; q=p; } } p=p->next; } if (q==NULL)//若是沒有找到位置 { return 0; } else//找到了最佳位置 { temp->next=q; temp->front=q->front; temp->date.address=q->date.address; q->front->next=temp; q->front=temp; q->date.size=surplus; q->date.address+=size; return 1; } } int free(int ID)//主存回收 { Free_Node *p=block_first->next; while(p) { if (p->date.ID==ID)//找到要回收的ID區域 { p->date.flag=FREE; p->date.ID=FREE; //判斷P與先後區域關係 if (p->front->date.flag==FREE&&p->next->date.flag!=FREE) { p->front->date.size+=p->date.size; p->front->next=p->next; p->next->front=p->front; } if (p->front->date.flag!=FREE&&p->next->date.flag==FREE) { p->date.size+=p->next->date.size; if(p->next->next) { p->next->next->front=p; p->next = p->next->next; } else p->next=p->next->next; } if(p->front->date.flag==FREE&&p->next->date.flag==FREE) { p->front->date.size+=p->date.size+p->next->date.size; if(p->next->next) { p->next->next->front=p->front; p->front->next=p->next->next; } else p->front->next=p->next->next; } if(p->front->date.flag!=FREE&&p->next->date.flag!=FREE) {// } break; } p=p->next; } cout<<"回收成功!"<<endl; return 1; } void Destroy(Free_Node *p) { } void show() { cout<<"------------------"<<endl; cout<<"內存分配狀況"<<endl; cout<<"------------------"<<endl; Free_Node *p=block_first->next; while(p) { cout<<"分區號:"; if (p->date.ID==FREE) cout<<"FREE"<<endl; else cout<<p->date.ID; cout<<"起始地址:"<<p->date.address<<endl; cout<<"內存大小:"<<p->date.size<<endl; cout<<"分區狀態:"; if (p->date.flag==FREE) cout<<"空閒"<<endl; else cout<<"已分配"<<endl; cout<<"------------------"<<endl; p=p->next; } } void menu()//菜單 { int tag=0; int ID; init(); cout<<"分區模擬:"<<endl; while(tag!=5) { cout<<"親輸入要進行的操做:"<<endl; cout<<"1-首次適應算法,2-最佳適應算法,3-內存回收,4-顯示內存情況,5-退出"<<endl; cin>>tag; switch(tag) { case 1: alloc(tag); break; case 2: alloc(tag); break; case 3: cout<<"親輸入須要回收的ID號:"<<endl; cin>>ID; free(ID); break; case 4: show(); break; } } } void main() { menu(); }
八、調試分析:
首次適應算法:
最佳適應算法:
九、算法優缺點:
對於首次適應算法:
該算法傾向於優先利用內存中低址部分的空閒分區,從而保留了高址部分的大空閒區,這爲之後到達的大做業分配大的內存空間創造了條件。
缺點爲低址部分不斷被劃分,會留下許多難以利用的,很小的空閒分區,稱爲碎片。而每次查找又都是從低址部分開始的,這無疑又會增長查找可用空閒分區時的開銷。
對於最佳適應算法:
它從所有空閒區中找出能知足做業要求的、且大小最小的空閒分區,這種方法能使碎片儘可能小。爲適應此算法,空閒分區表(空閒區鏈)中的空閒分區要按從小到大進行排序,自表頭開始查找到第一個知足要求的自由分區分配。該算法保留大的空閒區,但形成許多小的空閒區。
缺點爲會形成不少細小的碎片,這些小碎片不能知足大多數進程請求內存的大小,因此會形成內存浪費。