- 姓名:巫艳珍
- 学号:201821121034
- 班级:计算1812
1. 记录内存空间使用情况
- 记录内存当前空间的使用情况,用指针的形式,分别将空闲分区表和进程使用链表打印出:
- 进程使用了哪些空间,包括pid,大小,起始地址,进程名,next指向下一分区
2. 记录空闲分区
根据实验PPT给出的各部分的结构体分区
- 空闲分区表分区大小以及起始地址,next指向下一分区的地址
- 初始化空闲分区链表
3. 内存分配算法
最佳适应算法(Best Fit):
它从全部空闲区中找出能满足作业要求的、且大小最小的空闲分区,这种方法能使碎片尽量小。为适应此算法,空闲分区表(空闲区链)中的空闲分区要按从小到大进行排序,自表头开始查找到第一个满足要求的自由分区分配。该算法保留大的空闲区,但造成许多小的空闲区。
实现代码如下,排序算法:
void rearrange_BF(){ //最佳适应算法,空闲分区按大小从小到大排序 if(free_block == NULL || free_block->next == NULL) return; FBT *t1,*t2,*head; head = free_block; for(t1 = head->next;t1;t1 = t1->next){ for(t2 = head;t2 != t1;t2=t2->next){ if(t2->size > t2->next->size){ int tmp = t2->start_addr; t2->start_addr = t2->next->start_addr; t2->next->start_addr = tmp; tmp = t2->size; t2->size = t2->next->size; t2->next->size = tmp; } } } }
4. 内存释放算法
进程终止,释放内存,如何释放,如何更新内存空闲分区表。给出算法源代码,并解释。
//释放链表节点 int dispose(AB *free_ab){ /*释放ab数据结构节点*/ AB *pre,*ab; if(free_ab == allocated_block_head){ //如果要是释放第一个节点 allocated_block_head = allocated_block_head->next; free(free_ab); return 1; } pre = allocated_block_head; ab = allocated_block_head->next; while(ab!=free_ab){ pre = ab; ab = ab->next; } pre->next = ab->next; free(ab); return 2; }
//更新分区表 int free_mem(AB *ab){ //将已分配区归还 int algorithm = ma_algorithm; FBT *fbt,*pre,*work; fbt = (FBT*)malloc(sizeof(FBT)); if(!fbt) return -1; fbt->size = ab->size; fbt->start_addr = ab->start_addr; //插至末尾 work = free_block; if(work == NULL){ free_block = fbt; fbt->next == NULL; }else{ while(work ->next != NULL){ work = work->next; } fbt->next = work->next; work->next = fbt; } //重新排布 rearrange_BF(); //合并分区 pre = free_block; while(pre->next){ work = pre->next; if(pre->start_addr + pre->size == work->start_addr ){ pre->size = pre->size + work->size; pre->next = work->next; free(work); continue; }else{ pre = pre->next; } } //按照当前算法排序,即最佳适配算法 rearrange(ma_algorithm); return 1; } //找到pid对应的链表节点 AB *find_process(int pid){ AB *tmp = allocated_block_head; while(tmp != NULL){ if(tmp->pid == pid){ return tmp; } tmp = tmp->next; } printf("e[0;31;1m 查找失败! e[0m ",pid); return NULL; } //杀死进程 int kill_process(int pid){ AB *ab; ab = find_process(pid); if(ab!=NULL){ free_mem(ab); //释放ab所表示的分配表 dispose(ab); //释放ab数据结构节点 return 0; }else{ return -1; } }
首先释放链表结点,利用free()不断释放结点,更新分区表,进行可能的合并,将释放的结点放置在空闲分区的末结点,对空闲的链表进行排列,使用的是BF算法,若空闲区相邻,则做合并的操作,然后将空闲链表按照BF算法进行排序。
5. 运行结果
(1)产生测试数据
随机为3个进程分配、释放内存10次以上,即随机产生10组以上数据:(进程Pi 分配内存大小) 或者 (进程Pi结束)
(2)解释结果
每一次内存分配或释放,内存的示意图是怎样的。给出4组分析即可。
- 内存大小设为1024,创建进程pro1,并分配内存为57
- 创建进程pro3,起始地址为57,大小为82
- 分别释放pro1和pro2之后创建进程pro2,大小为79:
- 采用BF算法,为三个进程分配空间,pro3大小为83,pro2从地址83开始,大小为46,pro1从地址120开始,大小为102,剩余内存为802。释放了pro1之后再进行分配,从地址120开始
测试的代码(部分函数在前文):
int main(int argc, char const *argv[]){ int flag1,flag2; int total=0; free_block = init_free_block(mem_size); //初始化空闲区 Pro pro[3];//存放要加载的进程数为3 init_program(pro,3);//初始化进程 srand( (unsigned)time( NULL ) ); for(int i=0;i<DATA_NUM;++i) { flag1=rand()%2; int count=0; for(int j=0;j<3;++j){ if(pro[j].pid!=-1) count++; } if((count==3 && flag1==0)||total==10) flag1=1; if(count==0 && flag1==1) flag1=0; if(flag1==0)//为进程分配内存 { //随机一个未分配内存的进程 do{ flag2=rand()%3; }while(pro[flag2].pid!=-1); new_process(pro[flag2]);//分配内存空间 pro[flag2].pid=pid; total++; view(); } else//释放进程占用的内存空间 { //随机找一个可释放进程 do{ flag2=rand()%3; }while(pro[flag2].pid==-1); kill_process(pro[flag2].pid);//释放内存空间 pro[flag2].pid=-1; view();//显示内存使用情况 } } } //初始化空闲分区链表 FBT *init_free_block(int mem_size){ FBT *fb; fb = (FBT*)malloc(sizeof(FBT)); if(fb==NULL){ printf("无内存 "); return NULL; } fb->size = mem_size; fb->start_addr = MEM_START; fb->next = NULL; return fb; } //更新分区表 int free_mem(AB *ab){ /* 将ab所表示的已分配区归还,并进行可能的合并 */ int algorithm = ma_algorithm; FBT *fbt,*pre,*work; fbt = (FBT*)malloc(sizeof(FBT)); if(!fbt) return -1; fbt->size = ab->size; fbt->start_addr = ab->start_addr; //插至末尾 work = free_block; if(work == NULL){ free_block = fbt; fbt->next == NULL; }else{ while(work ->next != NULL){ work = work->next; } fbt->next = work->next; work->next = fbt; } //按地址重新排布 rearrange_BF(); //合并可能分区;即若两空闲分区相连则合并 pre = free_block; while(pre->next){ work = pre->next; if(pre->start_addr + pre->size == work->start_addr ){ pre->size = pre->size + work->size; pre->next = work->next; free(work); continue; }else{ pre = pre->next; } } //按照当前算法排序 rearrange(ma_algorithm); return 1; }//寻找是否有分区可以非进程分配 int find_free_mem(int request){ FBT *tmp = free_block; int mem_sum = 0; while(tmp){ if(tmp->size >= request){ //可以直接分配 return 1; } mem_sum += tmp->size; tmp = tmp->next; } if(mem_sum >= request){ //合并后分配 return 0; }else{ //没有足够的空间可供分配 return -1; } } //将已分配表按起始地址从大到小排序 void sort_AB(){ if(allocated_block_head == NULL || allocated_block_head->next == NULL) return; AB *t1,*t2,*head; head = allocated_block_head; for(t1 = head->next;t1;t1 = t1->next){ for(t2 = head;t2 != t1;t2=t2->next){ if(t2->start_addr > t2->next->start_addr){ int tmp = t2->start_addr; t2->start_addr = t2->next->start_addr; t2->next->start_addr = tmp; tmp = t2->size; t2->size = t2->next->size; t2->next->size = tmp; } } } } //重新分配 void reset_AB(int start){ AB *tmp = allocated_block_head; while(tmp != NULL){ tmp->start_addr = start; start += tmp->size; tmp = tmp->next; } } void memory_compact(){ //进行内存紧缩 FBT *fbttmp = free_block; AB *abtmp = allocated_block_head; //检测剩余内存 int sum = 0; while(fbttmp!=NULL){ sum += fbttmp->size; fbttmp = fbttmp->next; } //合并区块为一个 fbttmp = free_block; fbttmp->size = sum; fbttmp->start_addr = 0; fbttmp->next=NULL; //释放多余分区 FBT *pr = free_block->next; while(pr != NULL){ fbttmp = pr->next; free(pr); pr = fbttmp; } //重新排序已分配空间 sort_AB(); reset_AB(sum); } //执行分配内存 void do_allocate_mem(AB *ab){ int request = ab->size; FBT *tmp = free_block; while(tmp != NULL){ if(tmp->size >= request){ //分配 ab->start_addr = tmp->start_addr; int shengyu = tmp->size - request; tmp->size = shengyu; tmp->start_addr = tmp->start_addr + request; return ; } tmp = tmp->next; } } int allocate_mem(AB *ab){ /*分配内存模块*/ FBT *fbt,*pre; int request_size=ab->size; fbt = pre = free_block; int f = find_free_mem(request_size); if(f == -1){ printf("空闲内存不足,内存分配失败! "); return -1; }else{ if(f == 0){ //需要内存紧缩才能分配 memory_compact(); } //执行分配 do_allocate_mem(ab); } //重新排布空闲分区 rearrange(ma_algorithm); return 1; } //为进程分配内存 int new_process(Pro pro){ AB *ab; int ret; ab = (AB*)malloc(sizeof(AB)); if(!ab) exit(-5); ab->next=NULL; pid++;//记录id strcpy(ab->process_name,pro.process_name); ab->pid = pid; ab->size=pro.size+rand()%ALLOC_SIZE;//随机分配内存 ret = allocate_mem(ab); //从空闲分区分配内存,ret==1表示分配成功 if((ret == 1) && (allocated_block_head == NULL)){ allocated_block_head = ab; return 1; }else if(ret == 1){ ab->next = allocated_block_head; allocated_block_head = ab; return 2; }else if(ret == -1){ printf("e[0;31;1m 内存分配失败! e[0m "); free(ab); return -1; } return 3; } //初始化进程 void init_program(Pro pro[],int n) { for(int i=0;i<n;++i){ pro[i].size=PROCESS_SIZE; pro[i].pid=-1; sprintf(pro[i].process_name,"pro%d",i+1); } } //利用BF算法整理空闲块 void rearrange(int algorithm){ rearrange_BF(); }
参考链接:
https://blog.csdn.net/u011070169/article/details/53177987
https://github.com/City-Zero/LinuxTest/blob/master/OSex/mem_manager/mm.c