操作系统第5次实验报告:内存管理
0. 个人信息
- 姓名 雷坛春
- 学号 201821121030
- 班级 计算1811
1. 记录内存空间使用情况
参照内存管理PPT,自定义一个结构体allocated_block,别名为AB,表示每个进程分配到的内存块描述,包括进程标识符、进程大小等。再接着定义allocated_block_head,刚开始置为NULL,表示无分配内存状况。
当每分配一次进程空间,则就在allocated_block_head后加入一个结点,如果删除一个进程,则释放一个结点。
/*每个进程分配到的内存块描述*/ typedef struct allocated_block{ int pid; int size; int start_addr; char process_name[NAME_LEN]; struct allocated_block *next; }AB; /*进程分配内存块链表的首指针*/ AB *allocated_block_head = NULL;
2. 记录空闲分区
定义结构体free_block_type描述每一个空闲块的数据结构,有空闲块大小、空闲块起始地址等,定义一个指针free_block并置为null指向链表表头,并且初始化。
/*描述每一个空闲块的数据结构*/ typedef struct free_block_type{ int size; int start_addr; struct free_block_type *next; }FBT; FBT *free_block;//指向内存中空闲块链表的首指针
3. 内存分配算法
首次适应算法:将空闲的内存区按其在储存空间中的起始地址递增的顺序排列,为作业分配储存空间时,从空闲区链的始端开始查找,选择第一个满足要求的空闲区,而不管它究竟有多大
//将已分配表按起始地址从大到小排序 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; } } } } 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("空闲内存不足,内存分配失败!\n"); return -1; }else{ if(f == 0){ //需要内存紧缩才能分配 memory_compact(); } //执行分配 do_allocate_mem(ab); } //重新排布空闲分区 rearrange(ma_algorithm); return 1; } void rearrange_FF(){ /*空闲区大小按起始地址升序排序*/ //使用冒泡排序方法排序 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->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; } } } }
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){ /* 将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_FF(); //若两空闲分区相连则合并 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; }
5. 运行结果
终端编译运行
运行结果
3.结果解释
第一次操作为进程process-02分配了从0开始,大小为62的一块内存单元,分配后空闲分区内存剩余地址从62开始,大小为962的一块区域。
第二次操作释放了进程process-02的内存空间,释放后空闲分区内存剩余地址从0开始,大小为1024的一块区域。
第三次操作为进程process-02分配了从0开始,大小为88的一块内存单元,分配后空闲分区内存剩余地址从88开始,大小为936的一块区域。
第四次操作为进程process-01分配了从88开始,大小为65的一块内存单元,分配后空闲分区内存剩余地址从153开始,大小为871的一块区域。
第五次操作为进程process-03分配了从153开始,大小为34的一块内存单元,分配后空闲分区内存剩余地址从187开始,大小为837的一块区域。
第六次操作释放进程process-03,释放后后空闲分区内存剩余地址从153开始,大小为871的一块区域。