操作系统第5次实验报告:内存管理

Posted caibanye

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了操作系统第5次实验报告:内存管理相关的知识,希望对你有一定的参考价值。

  • 李微微
  • 201821121001
  • 计算1811

1. 记录内存空间使用情况

     ①根据实验课上的PPT,记录进程使用了哪些内存空间,用链表实现。在结构体里声明进程ID、占用大小、起始地址、进程名和指向自己类型的指针,用于存放进程信息。

/*记录内存空间使用情况*/
typedef struct allocated_block{
    int pid;
    int size;
    int start_addr;
    char process_name[PNAME_LEN];
    struct allocated_block *next;
}AB;

     ②定义一个全局指针变量,作为进程分配内存块的首指针,指向链表头结点。在分配内存时,用指针将该结点加入链表;在释放内存时,用指针将该结点从链表中删除。

AB *allocated_block_head = NULL; 

2. 记录空闲分区

     ①同样用链表记录空闲分区,同样定义一个结构体,声明占用大小、起始地址和指向自己类型的指针。

typedef struct free_block_type{
     int size;
     int start_addr;
     struct free_block_type *next;
}FBT;

     ②同样定义一个全局指针变量,作为内存中空闲块链表首指针,指向链表头结点。在刚初始化内存空间时,内存空间都是空闲分区;当分配内存空间后,内存管理算法会从空闲分区分出一块,这样就会导致空闲分区不连续。所以将空闲分区结点插入,并重新排序。释放内存时,分区结点从链表中删除。

FBT *free_block;          //指向内存中空闲块链表的首指针

3. 内存分配算法

  • 使用的内存分配:首次适配
  • 代码包括分配内存算法、应用分配内存算法的模块(包括内存紧缩后分配函数、重排空闲分区函数)、为进程分配内存模块。
  • 算法的本质是,把最合适的空闲区分配给进程。空闲区足够大则分割,分割后会打乱空闲区,就需要把空闲区加入链表,重新排序;空闲区不够则用内存紧缩,合并空闲分区,再分配。
 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 residue = tmp->size - request;
             tmp->size = residue;
             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("Not enough free memory!
");
         return -1;
     }else{
         if(f == 0){                //内存紧缩后分配
             Memory_Compact();
         }
         Do_Allocate_Mem(ab);       //分配
     }
     Rearrange(ma_algorithm);       //重排空闲分区
     return 1;
 }
 int Alloc_Process(PRO prc){        //为进程分配内存
     AB *ab;
     int ret;
     ab = (AB*)malloc(sizeof(AB));
     if(!ab) exit(-5);
     ab->next=NULL;
     pid++;
     strcpy(ab->process_name,prc.process_name);
     ab->pid = pid;
     ab->size=prc.size+rand()%ALLOC_SIZE; //随机分配内存
     ret = Allocate_Mem(ab);              //分配内存,ret==1表示分配成功
     if((ret == 1) && (allocated_block_head == NULL)){ //若allocated_block_head尚未赋值
         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("Fail!
");
         free(ab);
         return -1;
     }
     return 3;
 }
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);
 }

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_FIR();                   //首次适配算法
     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 Kill_Process(int pid){           //释放进程内存
     AB *ab;
     ab = Find_Process(pid);
     if(ab!=NULL){
         Free_Mem(ab);                //释放分配表
         Dispose(ab);                 //释放节点
         return 0;
     }else{
         return -1;
     }
 }

5. 运行结果

(1)产生测试数据

随机为3个进程分配、释放内存10次以上,即随机产生10组以上数据:

#define PROCESS_NUM 3          //进程数
int main(int argc, char const *argv[]){ int sel1,sel2; int total=0; //记录分配内存的次数 free_block=Init_Free_Block(mem_size); //初始化空闲区 PRO prc[PROCESS_NUM]; //存放要加载的进程 Init_Program(prc,PROCESS_NUM); //对这几个程进程进行初始化 srand((unsigned)time(NULL)); for(int i=0;i<DATA_NUM;++i) { sel1=rand()%2; int count=0; //统计三个进程中有多少个进程已经分配内存 for(int j=0;j<PROCESS_NUM;++j){ if(prc[j].pid!=-1) count++; } //如果全部分配进程或者进程分配到达10次,那么就不能继续分配内存 if((count==PROCESS_NUM && sel1==0)||total==10) sel1=1; //如果全部未分配进程,那么就不能继续释放内存 324 if(count==0 && sel1==1) sel1=0; if(sel1==0) //为进程分配内存 { //随机找到一个未分配内存的进程 do{ sel2=rand()%PROCESS_NUM; }while(prc[sel2].pid!=-1); Alloc_Process(prc[sel2]); //分配内存空间 prc[sel2].pid=pid; //改变标记 total++; Display_Mem_Usage(); //显示结果 } else //释放进程占用的内存空间 { do{ //随机找到一个可释放进程 sel2=rand()%PROCESS_NUM; }while(prc[sel2].pid==-1); Kill_Process(prc[sel2].pid);//释放内存空间 prc[sel2].pid=-1; //改变标记 Display_Mem_Usage(); //显示 } } }

(2)解释结果

运行结果:

 技术图片

 

 解释:

①第一次内存分配:进程名为process-03,起始地址为0,进程占用内存大小为98;剩余空闲分区首地址为98,大小为926。

分配结果:

技术图片

释放进程process-03:

技术图片

②第二次内存分配:进程名为process-02,起始地址为0,进程占用内存大小为107;剩余空闲分区首地址为107,大小为917。

分配结果:

技术图片

释放进程process-02:

技术图片

③第三次内存分配:进程名为process-03,起始地址为0,进程占用内存大小为107;剩余空闲分区首地址为107,大小为917。未释放进程。

分配结果:

技术图片

 

 ④第四次内存分配:进程名为process-01,起始地址为96,进程占用内存大小为67;剩余空闲分区首地址为163,大小为861。未释放进程。

技术图片

6. 源码

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<time.h>
  5
  6 #define PNAME_LEN 32           //进程名
  7 #define MEM_SIZE 1024          //内存大小
  8 #define MEM_START 0            //起始位置
  9 #define MATE_FIR 1             //定义首次适配算法
 10 #define DATA_NUM 20            //定义产生数据的组数
 11 #define PROCESS_NUM 3          //进程数
 12 #define PROCESS_SIZE 10        //进程大小
 13 #define ALLOC_SIZE 100         //随机分配最大值
 14
 15 /*记录内存空间使用情况,每个进程分配到的内存块描述*/
 16 typedef struct allocated_block{
 17     int pid;
 18     int size;
 19     int start_addr;
 20     char process_name[PNAME_LEN];
 21     struct allocated_block *next;
 22 }AB;
 23 /*记录空闲分区,描述每一个空闲块的数据结构*/
 24 typedef struct free_block_type{
 25     int size;
 26     int start_addr;
 27     struct free_block_type *next;
 28 }FBT;
 29 /*描述每个进程结构*/
 30 typedef struct Process{
 31     int size;
 32     int pid;
 33     char process_name[PNAME_LEN];
 34 }PRO;
 35
 36 FBT *free_block;//指向内存中空闲块链表的首指针
 37 /*进程分配内存块链表的首指针*/
 38 AB *allocated_block_head = NULL;
 39
 40 static int pid = 0;          /*初始pid*/
 41
 42 int mem_size = MEM_SIZE;     //内存大小
 43 int ma_algorithm = MATE_FIR; //当前分配算法为首次适配算法
 44 int min_mem_size = 0;        //设置剩余分区过小的标志
 45
 46 //初始化空闲分区链表
 47 FBT *Init_Free_Block(int mem_size){
 48     FBT *fb;
 49     fb = (FBT*)malloc(sizeof(FBT));
 50     if(fb==NULL){
 51         printf("No mem
");
 52         return NULL;
 53     }
 54     fb->size = mem_size;
 55     fb->start_addr = MEM_START;
 56     fb->next = NULL;
 57     return fb;
 58 }
 59
 60 void Rearrange_FIR(){              //首次适配算法,冒泡起始地址升序
 61     if(free_block == NULL || free_block->next == NULL)
 62         return;
 63     FBT *t1,*t2,*head;
 64     head = free_block;
 65     for(t1 = head->next;t1;t1 = t1->next){
 66         for(t2 = head;t2 != t1;t2=t2->next){
 67             if(t2->start_addr > t2->next->start_addr){
 68                 int tmp = t2->start_addr;
 69                 t2->start_addr = t2->next->start_addr;
 70                 t2->next->start_addr = tmp;
 71                 tmp = t2->size;
 72                 t2->size = t2->next->size;
 73                 t2->next->size = tmp;
 74             }
 75         }
 76     }
 77 }
 78 void Rearrange(int algorithm){  //按指定的算法整理内存空闲块链
 79     Rearrange_FIR();
 80 }
 81
 82 int Display_Mem_Usage(){            //显示当前内存的使用情况
 83     FBT *fbt = free_block;
 84     AB *ab = allocated_block_head;
 85     printf("------------------------------------------------------------------
");
 86     printf("Free Memory:
");       //空闲内存
 87     printf("%20s %20s
","     start_addr","       size");
 88     while(fbt!=NULL){
 89         if(fbt->size!=0)
 90             printf("%20d %20d
",fbt->start_addr,fbt->size);
 91         fbt = fbt->next;
 92     }
 93     printf("
");
 94     printf("Used Memory:
");       //已分配内存
 95     printf("%10s %20s %20s %10s
","PID","ProcessName","start_addr","size");
 96     while(ab != NULL){
 97         printf("%10d %20s %20d %10d
",ab->pid,ab->process_name,ab->start_addr,ab->size);
 98         ab = ab->next;
 99     }
100     printf("------------------------------------------------------------------
");
101     return 0;
102 }
103 int Dispose(AB *free_ab){                  //释放链表ab节点
104     AB *pre,*ab;
105     if(free_ab == allocated_block_head){    //若释放首节点
106         allocated_block_head = allocated_block_head->next;
107         free(free_ab);
108         return 1;
109     }
110     pre = allocated_block_head;             //否则
111     ab = allocated_block_head->next;
112     while(ab!=free_ab){
113         pre = ab;
114         ab = ab->next;
115     }
116     pre->next = ab->next;
117     free(ab);
118     return 2;
119 }
120 int Free_Mem(AB *ab){                //更新分区表归还已分配区,以及可能的合并
121     int algorithm = ma_algorithm;
122     FBT *fbt,*pre,*work;
123     fbt = (FBT*)malloc(sizeof(FBT));
124     if(!fbt) return -1;
125
126     fbt->size = ab->size;
127     fbt->start_addr = ab->start_addr; //插入链尾
128     work = free_block;
129     if(work == NULL){
130         free_block = fbt;
131         fbt->next == NULL;
132     }else{
133         while(work ->next != NULL){
134             work = work->next;
135         }
136         fbt->next = work->next;
137         work->next = fbt;
138     }
139     Rearrange_FIR();                   //首次适配算法
140     pre = free_block;
141     while(pre->next){
142         work = pre->next;
143         if(pre->start_addr + pre->size == work->start_addr ){
144             pre->size = pre->size + work->size;
145             pre->next = work->next;
146             free(work);
147             continue;
148         }else{
149             pre = pre->next;
150         }
151     }
152     Rearrange(ma_algorithm);          //按照当前算法排序
153     return 1;
154 }
155 AB *Find_Process(int pid){            //找到pid对应的链表节点
156     AB *tmp = allocated_block_head;
157     while(tmp != NULL){               //如果找不到
158         if(tmp->pid == pid){
159             return tmp;
160         }
161         tmp = tmp->next;
162     }
163     printf("Process with PID %d not found!
",pid);
164     return NULL;
165 }
166 int Kill_Process(int pid){           //释放进程内存
167     AB *ab;
168     ab = Find_Process(pid);
169     if(ab!=NULL){
170         Free_Mem(ab);                //释放分配表
171         Dispose(ab);                 //释放节点
172         return 0;
173     }else{
174         return -1;
175     }
176 }
177 int Find_Free_Mem(int request){      //寻找非进程分配分区
178     FBT *tmp = free_block;
179     int mem_sum = 0;
180     while(tmp){
181         if(tmp->size >= request){    //若可以直接分配
182             return 1;
183         }
184         mem_sum += tmp->size;
185         tmp = tmp->next;
186     }
187     if(mem_sum >= request){          //若可以合并后分配
188         return 0;
189     }else{                           //若空间不足
190         return -1;
191     }
192 }
193 void Sort_AB(){                      //将已分配表按起始地址从大到小排序
194     if(allocated_block_head == NULL || allocated_block_head->next == NULL)
195         return;
196     AB *t1,*t2,*head;
197     head = allocated_block_head;
198     for(t1 = head->next;t1;t1 = t1->next){
199         for(t2 = head;t2 != t1;t2=t2->next){
200             if(t2->start_addr > t2->next->start_addr){
201                 int tmp = t2->start_addr;
202                 t2->start_addr = t2->next->start_addr;
203                 t2->next->start_addr = tmp;
204                 tmp = t2->size;
205                 t2->size = t2->next->size;
206                 t2->next->size = tmp;
207             }
208         }
209     }
210 }
211 void Reset_AB(int start){            //重新分配内存地址
212     AB *tmp = allocated_block_head;
213     while(tmp != NULL){
214         tmp->start_addr = start;
215         start += tmp->size;
216         tmp = tmp->next;
217     }
218 }
219 void  Memory_Compact(){             //进行内存紧缩
220     FBT *fbttmp = free_block;
221     AB *abtmp = allocated_block_head;
222     int sum = 0;
223     while(fbttmp!=NULL){            //检测剩余内存
224         sum += fbttmp->size;
225         fbttmp = fbttmp->next;
226     }
227     fbttmp = free_block;            //合并区块
228     fbttmp->size = sum;
229     fbttmp->start_addr = 0;
230     fbttmp->next=NULL;
231     FBT *pr = free_block->next;      //释放分区
232     while(pr != NULL){
233         fbttmp = pr->next;
234         free(pr);
235         pr = fbttmp;
236     }
237     Sort_AB();                      //已分配空间重新排序
238     Reset_AB(sum);
239 }
240 void Do_Allocate_Mem(AB *ab){       //分配内存
241     int request = ab->size;
242     FBT *tmp = free_block;
243     while(tmp != NULL){
244         if(tmp->size >= request){
245             ab->start_addr = tmp->start_addr;
246             int residue = tmp->size - request;
247             tmp->size = residue;
248             tmp->start_addr = tmp->start_addr + request;
249             return ;
250         }
251         tmp = tmp->next;
252     }
253 }
254 int Allocate_Mem(AB *ab){          //分配内存应用
255     FBT *fbt,*pre;
256     int request_size=ab->size;
257     fbt = pre = free_block;
258     int f = Find_Free_Mem(request_size); //寻找可分配
259     if(f == -1){                         //空闲内存不足
260         printf("Not enough free memory!
");
261         return -1;
262     }else{
263         if(f == 0){                //内存紧缩后分配
264             Memory_Compact();
265         }
266         Do_Allocate_Mem(ab);       //分配
267     }
268     Rearrange(ma_algorithm);       //重排空闲分区
269     return 1;
270 }
271 int Alloc_Process(PRO prc){        //为进程分配内存
272     AB *ab;
273     int ret;
274     ab = (AB*)malloc(sizeof(AB));
275     if(!ab) exit(-5);
276     ab->next=NULL;
277     pid++;
278     strcpy(ab->process_name,prc.process_name);
279     ab->pid = pid;
280     ab->size=prc.size+rand()%ALLOC_SIZE; //随机分配内存
281     ret = Allocate_Mem(ab);              //分配内存,ret==1表示分配成功
282     if((ret == 1) && (allocated_block_head == NULL)){ //若allocated_block_head尚未赋值
283         allocated_block_head = ab;
284         return 1;
285     }else if(ret == 1){                  //分配成功
286         ab->next = allocated_block_head;
287         allocated_block_head = ab;
288         return 2;
289     }else if(ret == -1){                 //分配不成功
290         printf("Fail!
");
291         free(ab);
292         return -1;
293     }
294     return 3;
295 }
296
297 //初始化进程
298 void Init_Program(PRO prc[],int n)
299 {
300     for(int i=0;i<n;++i){
301         prc[i].size=PROCESS_SIZE;
302         prc[i].pid=-1;
303         sprintf(prc[i].process_name,"process-%02d",i+1);
304     }
305 }
306
307 int main(int argc, char const *argv[]){
308     int sel1,sel2;
309     int total=0;                     //记录分配内存的次数
310     free_block=Init_Free_Block(mem_size); //初始化空闲区
311     PRO prc[PROCESS_NUM];            //存放要加载的进程
312     Init_Program(prc,PROCESS_NUM);   //对这几个程进程进行初始化
313     srand((unsigned)time(NULL));
314     for(int i=0;i<DATA_NUM;++i)
315     {
316         sel1=rand()%2;
317         int count=0;                  //统计三个进程中有多少个进程已经分配内存
318         for(int j=0;j<PROCESS_NUM;++j){
319             if(prc[j].pid!=-1)
320                 count++;
321         }        //如果全部分配进程或者进程分配到达10次,那么就不能继续分配内存
322         if((count==PROCESS_NUM && sel1==0)||total==10)
323             sel1=1;                   //如果全部未分配进程,那么就不能继续释放内存
324         if(count==0 && sel1==1)
325             sel1=0;
326         if(sel1==0)                    //为进程分配内存
327         {                              //随机找到一个未分配内存的进程
328             do{
329                 sel2=rand()%PROCESS_NUM;
330             }while(prc[sel2].pid!=-1);
331             Alloc_Process(prc[sel2]);  //分配内存空间
332             prc[sel2].pid=pid;         //改变标记
333             total++;
334             Display_Mem_Usage();       //显示结果
335         }
336         else                           //释放进程占用的内存空间
337         {
338             do{                         //随机找到一个可释放进程
339                 sel2=rand()%PROCESS_NUM;
340             }while(prc[sel2].pid==-1);
341             Kill_Process(prc[sel2].pid);//释放内存空间
342             prc[sel2].pid=-1;           //改变标记
343             Display_Mem_Usage();        //显示
344         }
345     }
346  }

以上是关于操作系统第5次实验报告:内存管理的主要内容,如果未能解决你的问题,请参考以下文章

操作系统第4次实验报告:文件系统

操作系统第2次实验报告:创建进程

操作系统第2次实验报告:创建进程

操作系统第4次实验报告:文件系统

操作系统第3次实验报告:管道

MIT-6.828 Lab 2实验报告