操作系统第5次实验报告:内存管理
- 姓名 邹文兵
- 学号 201821121028
- 班级 计算1811
1. 记录内存空间使用情况
记录内存空间使用情况:首先程序采用链式存储结构存储空闲分区链。定义一个空闲分区表的结构体,包括空闲分区表的id号,首地址、分区大小、分配标志。然后用结构体表示链表的每一个节点,包括分区表结构体、front和next指针。在进行内存分配时对不同进程进行适当地址分配,并记录分配信息在结构体中,最后定义一个p指针,让p指针遍历空闲分区链表将内存空间打印出来。
实现代码:
void show() { printf("------------------------------------------------------------------\n"); printf("内存分配情况:\n"); Free_Node *p=block_first->next; while(p) { cout<<"分区号:"; if (p->date.ID==FREE) printf("FREE\t"); else printf("%d\t",p->date.ID); printf("起始地址:%d\t",p->date.address); printf("内存大小:%d\t",p->date.size); printf("分区状态:"); if (p->date.flag==FREE) printf("空闲\n"); else printf("已分配\n"); p=p->next; } }
2. 记录空闲分区
空闲分区表的结构体:
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;
3. 内存分配算法
1、首次适应算法:
首次适应算法比较简单,只要找到满足条件的空闲区,就将此区的空间分配给进程。首先,用P指针遍历链表,找到第一个空间大于或者等于请求大小的位置,将此空间分配给进程,当此空闲区大小大于请求空间大小时,将空闲区分为两部分,一部分分配给进程,另一部分为空闲区,它的大小为之前空闲区大小减去分配给进程的空间大小。
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; }
2、最佳适应算法:
首先,定义一个p指针,让p指针遍历空闲分区链表,当找到第一个满足进程请求空间大小的空闲区时,记录此位置,并且保存请求大小与空闲分区实际大小的差值记为a,然后让p指针继续遍历空闲分区链表,每当满足请求内存大小小于空闲区大小时,就记录两者的差值并且记录为b,比较a与b的大小关系,当a>b时,将b的值赋予a,并且修改记录位置为此空闲区的位置。若,a<=b,不做操作。继续遍历链表,重复上面的操作,直到p->next指向null为止。
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; } }
4. 内存释放算法
内存回收算法:
内存回收时,回收分区与空闲分区有四种关系。第一种情况为回收分区r上临一个空闲分区,此时应该合并为一个连续的空闲区,其始址为r上相邻的分区的首地址,而大小为两者大小之和。第二种情况为回收分区r与下相邻空闲分区,合并后仍然为空闲区,该空闲区的始址为回收分区r的地址。大小为两者之和,第三种情况为回收部分r与上下空闲区相邻,此时将这三个区域合并,始址为r上相邻区域的地址,大小为三个分区大小之和。当回收部分r上下区域都为非空闲区域,此时建立一个新的空闲分区,并且加入到空闲区队列中去。
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; }break; } p=p->next; } cout<<"回收成功!"<<endl; return 1; }
5. 运行结果
(1)产生测试数据
写程序,产生测试数据(随机)。给出你的源码,以及你生成的测试数据是什么。
随机为3个进程分配、释放内存10次以上,即随机产生10组以上数据:(进程Pi 分配内存大小) 或者 (进程Pi结束)
int alloc(int tag) { int ID1,ID2,ID3; int size1,size2,size3; int i=0; srand((unsigned)time(NULL)); for(i;i<10;i++) //随机生成十组数据 { tag++; ID1=rand()%100; //进程1 size1=rand()%100; if (tag==1) first_fit(ID1,size1);//采用首次适应算法 else best_fit(ID1,size1);//采用最佳适应算法 ID2=rand()%100; //进程2 size2=rand()%100; if (tag==1) first_fit(ID2,size2);//采用首次适应算法 else best_fit(ID2,size2);//采用最佳适应算法 ID3=rand()%100; //进程3 size3=rand()%100; if (tag==1) first_fit(ID3,size3);//采用首次适应算法 else best_fit(ID3,size3);//采用最佳适应算法 show(); free(ID1); //进程1主存回收 show(); free(ID2); //进程2主存回收 show(); free(ID3); //进程3主存回收 show(); } }
运行结果截图:
(2)解释结果
第一次内存分配:进程1的进程号为44,申请内存大小为24,起始地址从空闲的0开始,即0到23处的内存分配给进程1;
第二次内存分配:进程2的进程号为70,申请内存大小为89,起始地址从空闲的24开始,即24到112处内存分配给进程2;
第三次内存分配:进程3的进程号为9,申请内存大小为21,起始地址从空闲的113开始,即113到133处内存分配给进程3;
由于初始化空闲内存大小为640,所以除去已分配的内存外其余还剩506的空闲内存,从134到640都为空闲内存。
第一次回收主存:回收进程1的内存,使地址0到23处地址状态改为空闲,即0到23和134到640都为空闲内存;
第二次回收主存:回收进程2的内存,使地址24到112处地址状态改为空闲,即0到112和134到640都为空闲内存;
第三次回收主存:回收进程3的内存,使地址113到133处地址状态改为空闲,即0到640都为空闲内存;