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

  • 姓名:吴永锋
  • 学号:201821121051
  • 班级:计算1812

 

动态分区分配是根据进程的实际需要,动态的为之分配内存空间。而在实现可变分区分配时,将涉及到分区分配中

所用的数据结构、分区分配算法和分区的分配与内存回收的过程。

    分区分配中的数据结构:(1)描述空闲块的数据结构。(2)内存块的描述。

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

分配内存区块表,包含被分配的内存区起始地址及大小和使用该内存的进程pid。 

 1 /*每个进程分配到的内存块描述*/
 2 typedef struct allocated_block{
 3     int pid;
 4     int size;            //进程大小
 5     int start_addr;        //进程分配到的内存块的起始地址
 6     char process_name[NAME_LEN];    //进程名 
 7     struct allocated_block *next;    //指向下一个进程控制块 
 8 }AB;
 9 
10 /*进程分配内存块链表的首指针*/
11 AB *allocated_block_head = NULL; 

2. 记录空闲分区

空闲内存区块表,包含该空闲区的起始地址以及大小。程序初始化链表仅一个节点,大小为默认大小。

1 /*描述每一个空闲块的数据结构*/
2 typedef struct free_block_type{
3     int size;            //空闲块大小 
4     int start_addr;        //空闲块起始位置 
5     struct free_block_type *next;    //指向下一个空闲块 
6 }FBT;
7 
8 FBT *free_block;//指向内存中空闲块链表的首指针

3. 内存分配算法

首次适应算法(First Fit):从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空闲区分配给

作业,这种方法的目的在于减少查找时间。为适应这种算法,空闲分区表(空闲区链)中的空闲分区要按地址由低到

高进行排序。该算法优先使用低址部分空闲区,在低址空间造成许多小的空闲区,在高地址空间保留大的空闲区。

  1 //执行分配内存
  2 void do_allocate_mem(AB *ab){
  3     int request = ab->size;
  4     FBT *tmp = free_block;
  5     while(tmp != NULL){
  6         if(tmp->size >= request){
  7             //分配
  8             ab->start_addr = tmp->start_addr;
  9             int shengyu = tmp->size - request;
 10             tmp->size = shengyu;
 11             tmp->start_addr = tmp->start_addr + request;
 12             
 13             return ;
 14         }
 15         tmp = tmp->next;
 16     }
 17 }
 18 
 19 int allocate_mem(AB *ab){
 20     /*分配内存模块*/
 21     FBT *fbt,*pre;
 22     int request_size=ab->size;
 23     fbt = pre = free_block;
 24     /*
 25     根据当前算法在空闲分区链表中搜索合适空闲分区进行分配,
 26         分配时注意以下情况:
 27     1. 找到可满足空闲分区且分配后剩余空间足够大,则分割
 28     2. 找到可满足空闲分区且但分配后剩余空间比较小,则一起分配
 29     3. 找不可满足需要的空闲分区但空闲分区之和能满足需要,
 30         则采用内存紧缩技术,进行空闲分区的合并,然后再分配
 31     4. 在成功分配内存后,应保持空闲分区按照相应算法有序
 32     5. 分配成功则返回1,否则返回-1
 33     */
 34     //尝试寻找可分配空闲,具体结果在函数中有解释
 35     int f = find_free_mem(request_size);
 36     if(f == -1){
 37         //不够分配
 38         printf("空闲内存不足,内存分配失败!\n");
 39         return -1;
 40     }else{
 41         if(f == 0){
 42             //需要内存紧缩才能分配
 43             memory_compact();
 44         }
 45         //执行分配
 46         do_allocate_mem(ab);
 47     }
 48     //重新排布空闲分区
 49     rearrange(ma_algorithm);
 50     return 1;
 51 }
 52 //为进程分配内存 
 53 int alloc_process(Prc prc){
 54     AB *ab;
 55     int ret;
 56     ab = (AB*)malloc(sizeof(AB));
 57     if(!ab) exit(-5);
 58     /*为ab赋值 */ 
 59     ab->next=NULL;
 60     pid++;//记录id 
 61     strcpy(ab->process_name,prc.process_name);
 62     ab->pid = pid; 
 63     ab->size=prc.size+rand()%ALLOC_SIZE;//随机分配内存 
 64 
 65     ret = allocate_mem(ab);        //从空闲分区分配内存,ret==1表示分配成功
 66     if((ret == 1) && (allocated_block_head == NULL)){
 67         /*如果此时allocated_block_head尚未赋值,则赋值*/
 68         allocated_block_head = ab;
 69         return 1;
 70     }else if(ret == 1){
 71         /*分配成功,将该分配块的描述插入已分配链表*/
 72         ab->next = allocated_block_head;
 73         allocated_block_head = ab;
 74         return 2;
 75     }else if(ret == -1){
 76         //分配不成功
 77         printf("\e[0;31;1m 内存分配失败! \e[0m\n");
 78         free(ab);
 79         return -1;
 80     }
 81     return 3;
 82 }
 83 
 84 void rearrange_FF(){
 85     /*首次适应算法,空闲区大小按起始地址升序排序*/
 86     //这里使用冒泡排序方法
 87     if(free_block == NULL || free_block->next == NULL)
 88         return;
 89     FBT *t1,*t2,*head;
 90     head = free_block;
 91     for(t1 = head->next;t1;t1 = t1->next){
 92         for(t2 = head;t2 != t1;t2=t2->next){
 93             if(t2->start_addr > t2->next->start_addr){
 94                 int tmp = t2->start_addr;
 95                 t2->start_addr = t2->next->start_addr;
 96                 t2->next->start_addr = tmp;
 97 
 98                 tmp = t2->size;
 99                 t2->size = t2->next->size;
100                 t2->next->size = tmp;
101             }
102         }
103     }
104 }

4. 内存释放算法

找到对应的链表节点,释放释放杀死进程的内存块,归还进程的已分配的存储空间,按大小从小到大排序,销毁杀死进程的结点。

 1 //释放链表节点
 2 int dispose(AB *free_ab){
 3     /*释放ab数据结构节点*/
 4     AB *pre,*ab;
 5     if(free_ab == allocated_block_head){
 6         //如果要是释放第一个节点
 7         allocated_block_head = allocated_block_head->next;
 8         free(free_ab);
 9         return 1;
10     }
11     pre = allocated_block_head;
12     ab = allocated_block_head->next;
13     while(ab!=free_ab){
14         pre = ab;
15         ab = ab->next;
16     }
17     pre->next = ab->next;
18     free(ab);
19     return 2;
20 }
21 
22 //更新分区表
23 int free_mem(AB *ab){
24     /* 将ab所表示的已分配区归还,并进行可能的合并 */
25     int algorithm = ma_algorithm;
26     FBT *fbt,*pre,*work;
27     fbt = (FBT*)malloc(sizeof(FBT));
28     if(!fbt) return -1;
29     /*
30     进行可能的合并,基本策略如下?
31     1. 将新释放的结点插入到空闲分区队列末尾?
32     2. 对空闲链表按照地址有序排列?
33     3. 检查并合并相邻的空闲分区?
34     4. 将空闲链表重新按照当前算法排序
35     */
36     fbt->size = ab->size;
37     fbt->start_addr = ab->start_addr;
38 
39     //插至末尾
40     work = free_block;
41     if(work == NULL){
42         free_block = fbt;
43         fbt->next == NULL;
44     }else{
45         while(work ->next != NULL){
46             work = work->next;
47         }
48         fbt->next = work->next;
49         work->next = fbt;
50     }
51     //按地址重新排布
52     rearrange_FF();
53 
54     //合并可能分区;即若两空闲分区相连则合并
55     pre = free_block;
56     while(pre->next){
57         work = pre->next;
58         if(pre->start_addr + pre->size == work->start_addr ){
59             pre->size = pre->size + work->size;
60             pre->next = work->next;
61             free(work);
62             continue;
63         }else{
64             pre = pre->next;
65         }
66     }
67 
68     //按照当前算法排序
69     rearrange(ma_algorithm);
70     return 1;
71 }
72 
73 int kill_process(int pid){
74     AB *ab;
75     ab = find_process(pid);
76     if(ab!=NULL){
77         free_mem(ab);    //释放ab所表示的分配表
78         dispose(ab);    //释放ab数据结构节点
79         return 0;
80     }else{
81         return -1;
82     }
83 }

5. 运行结果

(1)产生测试数据

随机为3个进程分配、释放内存10次以上,即随机产生10组以上数据:(进程Pi 分配内存大小) 或者 (进程Pi结束)

int main(int argc, char const *argv[]){
    /* code */
    int sel1,sel2; 
    int total=0; //记录分配内存的次数 
    free_block = init_free_block(mem_size); //初始化空闲区
    
    Prc prc[PROCESS_NUM];//存放要加载的进程
    init_program(prc,PROCESS_NUM);//对这几个程进程进行初始化 
    srand( (unsigned)time( NULL ) );  
    
    for(int i=0;i<DATA_NUM;++i)
    {
        /*
           sel1=0表示为某进程分配内存空间 
           sel1=1表示为释放某进程占用的内存空间 
        */ 
        sel1=rand()%2;
        int count=0;
        //统计三个进程中有多少个进程已经分配内存 
        for(int j=0;j<PROCESS_NUM;++j){
            if(prc[j].pid!=-1)
                count++;
        }
        //如果全部分配进程或者进程分配到达5次,那么就不能继续分配内存改为释放内存 
        if((count==PROCESS_NUM && sel1==0)||total==5)
            sel1=1;
        //如果全部未分配进程,那么就不能继续释放内存 
        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)解释结果

程序中定义了内存大小为1024,

第一次,为进程process-03分配内存,起始地址为0,大小为106,分配后剩余空闲分区内存起始地址为106,大小为918。

第二次,为进程process-01分配内存,起始地址为106,大小为57,分配后剩余空闲分区内存起始地址为163,大小为861。

第三次,释放进程process-01的内存空间,释放后剩余空闲分区内存起始地址为106,大小为918。

第四次,释放进程process-03的内存空间,释放后剩余空闲分区内存起始地址为0,大小为1024。

参考博客:内存分配---FF、BF、WF三种算法

posted on 2020-05-17 16:27  矩小阵  阅读(364)  评论(0编辑  收藏  举报

导航