一、要求: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(); }
八、调试分析:
首次适应算法:
最佳适应算法:
九、算法优缺点:
对于首次适应算法:
该算法倾向于优先利用内存中低址部分的空闲分区,从而保留了高址部分的大空闲区,这为之后到达的大做业分配大的内存空间创造了条件。
缺点为低址部分不断被划分,会留下许多难以利用的,很小的空闲分区,称为碎片。而每次查找又都是从低址部分开始的,这无疑又会增长查找可用空闲分区时的开销。
对于最佳适应算法:
它从所有空闲区中找出能知足做业要求的、且大小最小的空闲分区,这种方法能使碎片尽可能小。为适应此算法,空闲分区表(空闲区链)中的空闲分区要按从小到大进行排序,自表头开始查找到第一个知足要求的自由分区分配。该算法保留大的空闲区,但形成许多小的空闲区。
缺点为会形成不少细小的碎片,这些小碎片不能知足大多数进程请求内存的大小,因此会形成内存浪费。