操作系统第5次实验报告:内存管理
姓名:蔡婷婷 学号:201821121003 班级:计算1811
1. 记录内存空间使用情况
①解释你是如何记录内存空间使用情况
建立一个链表来记录内存空间的使用情况,定义结构体allocated_block来存放加载至内存中的进程,定义一个指针allocated_block_head指向链表表头,对进程分配内存空间时,就将分配到内存空间的进程块节点添加到链表中;对进程内存进行释放时,就将成功释放的进程块节点从链表中删除。
②给出关键代码
23 typedef struct allocated_block{
24 int pid;
25 int size;
26 int start_addr;
27 char process_name[NAME_LEN];
28 struct allocated_block *next;
29 }AB;
42 AB *allocated_block_head = NULL;
2. 记录空闲分区
①用什么样的方法记录内存空闲区
定义空闲分区的结构体free_block_type,定义一个指针free block指向链表表头,对内存初始化后,空闲分区按从小到大进行排序,自表头开始查找到第一个满足要求的自由分区分配。
②给出关键代码
16 typedef struct free_block_type{
17 int size;
18 int start_addr;
19 struct free_block_type *next;
20 }FBT;
39 FBT *free_block;//指向内存中空闲块链表的首指针
3. 内存分配算法
①使用什么样的内存分配算法,并解释
内存分配:首次适配
先在在空闲分区链表中搜索合适空闲分区进行分配,分配时如果找到可满足空闲分区且分配后剩余空间足够大,则分割;如果找不可满足需要的空闲分区但空闲分区之和能满足需要,则采用内存紧缩技术,进行空闲分区的合并,然后再分配。
②给出算法源代码
331 void do_allocate_mem(AB *ab){
332 int request = ab->size;
333 FBT *tmp = free_block;
334 while(tmp != NULL){
335 if(tmp->size >= request){
336 //分配
337 ab->start_addr = tmp->start_addr;
338 int shengyu = tmp->size - request;
339 tmp->size = shengyu;
340 tmp->start_addr = tmp->start_addr + request;
341
342 return ;
343 }
344 tmp = tmp->next;
345 }
346 }
347
348 int allocate_mem(AB *ab){
349 /*分配内存模块*/
350 FBT *fbt,*pre;
351 int request_size=ab->size;
352 fbt = pre = free_block;
353 //尝试寻找可分配空闲,具体结果在函数中有解释
354 int f = find_free_mem(request_size);
355 if(f == -1){
356 //不够分配
357 printf("空闲内存不足,内存分配失败!\n");
358 return -1;
359 }else{
360 if(f == 0){
361 //需要内存紧缩才能分配
362 memory_compact();
363 }
364 //执行分配
365 do_allocate_mem(ab);
366 }
367 //重新排布空闲分区
368 rearrange(ma_algorithm);
369 return 1;
370 }
404 void rearrange_FF(){
405 /*首次适应算法,空闲区大小按起始地址升序排序*/
406 //这里使用冒泡排序方法
407 if(free_block == NULL || free_block->next == NULL)
408 return;
409 FBT *t1,*t2,*head;
410 head = free_block;
411 for(t1 = head->next;t1;t1 = t1->next){
412 for(t2 = head;t2 != t1;t2=t2->next){
413 if(t2->start_addr > t2->next->start_addr){
414 int tmp = t2->start_addr;
415 t2->start_addr = t2->next->start_addr;
416 t2->next->start_addr = tmp;
417
418 tmp = t2->size;
419 t2->size = t2->next->size;
420 t2->next->size = tmp;
421 }
422 }
423 }
424 }
4. 内存释放算法
①进程终止,释放内存,如何释放,如何更新内存空闲分区表。
释放:找到对应的链表节点,释放杀死进程的内存块,归还进程的已分配的存储空间,按从小到大排序,销毁杀死进程的结点。
更新:将新释放的结点插入到空闲分区队列末尾,对空闲链表按照地址有序排列,检查并合并相邻的空闲分区,将空闲链表重新按照首次适配算法排序
②给出算法源代码
152 int dispose(AB *free_ab){
153 /*释放ab数据结构节点*/
154 AB *pre,*ab;
155 if(free_ab == allocated_block_head){
156 //如果要是释放第一个节点
157 allocated_block_head = allocated_block_head->next;
158 free(free_ab);
159 return 1;
160 }
161 pre = allocated_block_head;
162 ab = allocated_block_head->next;
163 while(ab!=free_ab){
164 pre = ab;
165 ab = ab->next;
166 }
167 pre->next = ab->next;
168 free(ab);
169 return 2;
170 }
171
172 //更新分区表
173 int free_mem(AB *ab){
174 // 将ab所表示的已分配区归还,并进行可能的合并
175 int algorithm = ma_algorithm;
176 FBT *fbt,*pre,*work;
177 fbt = (FBT*)malloc(sizeof(FBT));
178 if(!fbt) return -1;
179 fbt->size = ab->size;
180 fbt->start_addr = ab->start_addr;
181 //插至末尾
182 work = free_block;
183 if(work == NULL){
184 free_block = fbt;
185 fbt->next == NULL;
186 }else{
187 while(work ->next != NULL){
188 work = work->next;
189 }
190 fbt->next = work->next;
191 work->next = fbt;
192 }
193 //按地址重新排布
194 rearrange_FF();
195 //合并可能分区;即若两空闲分区相连则合并
196 pre = free_block;
197 while(pre->next){
198 work = pre->next;
199 if(pre->start_addr + pre->size == work->start_addr ){
200 pre->size = pre->size + work->size;
201 pre->next = work->next;
202 free(work);
203 continue;
204 }else{
205 pre = pre->next;
206 }
207 }
208 //按照当前算法排序
209 rearrange(ma_algorithm);
210 return 1;
211 }
226 int kill_process(int pid){
227 AB *ab;
228 ab = find_process(pid);
229 if(ab!=NULL){
230 free_mem(ab); //释放ab所表示的分配表
231 dispose(ab); //释放ab数据结构节点
232 return 0;
233 }else{
234 return -1;
235 }
236 }
5. 运行结果
(1)产生测试数据
随机为3个进程分配、释放内存10次以上,即随机产生10组以上数据:(进程Pi 分配内存大小) 或者 (进程Pi结束)
①代码
61 int main(int argc, char const *argv[]){
62 /* code */
63 int sel1,sel2;
64 int total=0; //记录分配内存的次数
65 free_block = init_free_block(mem_size); //初始化空闲区
66
67 Prc prc[PROCESS_NUM];//存放要加载的进程
68 init_program(prc,PROCESS_NUM);//对这几个程进程进行初始化
69 srand( (unsigned)time( NULL ) );
70
71 for(int i=0;i<DATA_NUM;++i)
72 {
73 sel1=rand()%2;
74 int count=0;
75 //统计三个进程中有多少个进程已经分配内存
76 for(int j=0;j<PROCESS_NUM;++j){
77 if(prc[j].pid!=-1)
78 count++;
79 }
80 //如果全部分配进程或者进程分配到达10次,那么就不能继续分配内存
81 if((count==PROCESS_NUM && sel1==0)||total==10)
82 sel1=1;
83 //如果全部未分配进程,那么就不能继续释放内存
84 if(count==0 && sel1==1)
85 sel1=0;
86 if(sel1==0)//为进程分配内存
87 {
88 //随机找到一个未分配内存的进程
89 do{
90 sel2=rand()%PROCESS_NUM;
91 }while(prc[sel2].pid!=-1);
92 alloc_process(prc[sel2]);//分配内存空间
93 prc[sel2].pid=pid;//改变标记
94 total++;
95 display_mem_usage();//显示
96 }
97 else//释放进程占用的内存空间
98 {
99 //随机找到一个可释放进程
100 do{
101 sel2=rand()%PROCESS_NUM;
102 }while(prc[sel2].pid==-1);
103 kill_process(prc[sel2].pid);//释放内存空间
104 prc[sel2].pid=-1;//改变标记
105 display_mem_usage();//显示
106 }
107 }
108 }
②运行结果
(2)解释结果
分析前4组结果
①第一次组为进程process-01分配了从0开始,大小为56的一块内存单元,分配后空闲分区内存剩余地址从56开始,大小为968。
②第二次组为进程process-03分配了从56开始,大小为81的一块内存单元,分配后空闲分区内存剩余地址从137开始,大小为887。
③第三次组释放进程process-03从56开始大小为81的一块内存单元,分配后空闲分区内存剩余地址从56开始,大小为968。
④第四次组为进程process-03分配了从56开始,大小为78的一块内存单元,分配后空闲分区内存剩余地址从132开始,大小为892。