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

零、个人信息

  • 姓名:陈韵
  • 学号:201821121053
  • 班级:计算1812

一、记录内存空间使用情况

  •   空闲区和已分配区均采用的是链表的结构,每个结点代表一块空间,含有起始地址以及空间大小。

  空闲内存:                        

   

  已分配内存:

   

 

  •    过指针读取链表的每个节点,获取他们的size和start_addr。来确定这个结点所指向的空间,以及这块空间的使用情况。

   之后通过循环打印出每个空间的使用情况。

  /* 显示空闲区 */
    printf("空闲区:\n");
    printf("%20s %20s\n", "      起始地址", "       大小");
    while (fbt != NULL)
    {
        printf("%20d %20d\n", fbt->start_addr, fbt->size);
        fbt = fbt->next;
    }
    /* 显示已分配区 */
    printf("\n已分配区:\n");
    printf("%10s %20s %10s %10s\n", "PID", "进程名", "起始地址", " 大小");
    while (ab != NULL)
    {
        printf("%10d %20s %10d %10d\n", ab->pid, ab->process_name, ab->start_addr, ab->size);
        ab = ab->next;
    }

 

二、记录空闲分区

  •    使用的是链表结构记录空闲分区。

      

  •    初始化空闲分区块,我们需要先分配一块内存,默认大小为1024. 根据内存大小,进行空闲分区的初始化。
/*初始化空闲块,默认为一块,可以指定大小及起始地址*/
struct free_block_type *init_free_block(int mem_size)
{
    struct free_block_type *fb, *p;
    struct allocated_block *q;
    fb = (struct free_block_type *)malloc(sizeof(struct free_block_type));//空闲区头结点
    p = (struct free_block_type *)malloc(sizeof(struct free_block_type));//空闲区起始
    q = (struct allocated_block *)malloc(sizeof(struct allocated_block));//分配区头结点

    if (fb == NULL || p == NULL || q == NULL)
    {
        printf("没有分配内存\n");
        return NULL;
    }
    q->next = NULL;
    allocated_block_head = q;
p
->size = mem_size; p->start_addr = DEFAULT_MEM_START; p->next = NULL; fb->next = p; //头结点 return fb; }

     其中fb、q为空闲区链的指针,而q为已分配区链的指针。因为这是初始化,q获得了全部的内存空间。为了方便排序,fb作为q的前一个结点,即头结点。同样地,q为已分配区链的头结点。

三、内存分配算法

  •   这里采用的是最佳分配算法,最佳分配算法(BF)的策略:

  首先遍历整个空闲列表,找到和请求大小一样或更大的空闲块,然后返回这组候选者中最小的一块。

  它的优点十分明显,只需要遍历一次空闲列表,就足以找到正确的块并返回。

  •      利用BF算法重新排序:
 1 /*按BF算法重新整理内存空闲块链表*/
 2 void rearrange_BF()
 3 {
 4     //m代表头,p。q分别代表交换的两个节点 n代表交换截至位置
 5     struct free_block_type *p, *q, *m, *n;
 6 
 7     if (free_block->next->next != NULL)
 8     {
 9         n = NULL;
10         while (n != free_block->next->next)
11         {
12             m = free_block;
13             p = free_block->next;
14             q = p->next;
15             while (q != n)
16             {   //比较选出最小的一块
17                 if (p->size > q->size)
18                 {
19                     p->next = q->next;
20                     q->next = p;
21                     m->next = q;
22                 }
23                 //结点后移进行下一次比较
24                 m = m->next;
25                 p = m->next;
26                 q = p->next;
27             }
28             n = p;
29         }
30     }
31 }
  •   内存分配实现:
 1 int allocate_mem(struct allocated_block *ab)
 2 {
 3     struct free_block_type *p, *q, *temp;
 4     int sum = 0;
 5     if (free_block->next == NULL)
 6     {
 7         printf("no  memory");
 8         return 0;
 9     }
10     //BF算法进行整理内存
11     rearrange_BF();
12 
13     //从链首开始查找,如果找到,则开始分配,如果没有找到,采用分区紧缩技术,如果可以分配,则分配,不能分配,返回-1
14     if (ma_algorithm == MA_FF || ma_algorithm == MA_BF)
15     {
16         //开始寻找符合条件的节点
17         for (p = free_block, q = p->next; q && q->size < ab->size; p = p->next, q = p->next)
18             ;
19 
20         //找到
21         if (q)
22         {
23             //判断是否达到最小碎片程度
24 
25             if ((q->size - ab->size) <= MIN_SLICE)
26             {
27                 //全部分配
28                 ab->start_addr = q->start_addr;
29                 ab->size = q->size;
30                 //释放q节点
31                 p->next = q->next;
32                 free(q);
33             }
34             else
35             {
36                 ab->start_addr = q->start_addr;
37                 q->start_addr = q->start_addr + ab->size;
38                 q->size = q->size - ab->size;
39             }
40         }
41         //开始内存紧缩
42         else
43         {
44             for (q = free_block->next; q; q = q->next)
45             {
46                 sum += q->size;
47                 if (sum >= ab->size)
48                 {
49                     break;
50                 }
51             }
52             if (q)
53             {
54                 //第一个空闲分区大小更改为sum,并且除了第一个,其他结点全部删除
55                 free_block->next->size = sum;
56                 p = free_block->next;
57                 for (temp = p->next; temp != q; temp = p->next)
58                 {
59                     p->next = temp->next;
60                     free(temp);
61                 }
62                 p->next = q->next;
63                 free(q);
64 
65                 p->start_addr = p->start_addr + ab->size;
66                 p->size = p->size - ab->size;
67                 //如果剩余空间为0 则直接释放当前的空间
68             }
69             else
70 
71             {
72                 return -1;
73             }
74         }
75     return 1;
76  }
  • 根据BF算法在空闲分区链表中搜索合适空闲分区进行分配:

 

    1. 找到可满足空闲分区且分配后剩余空间足够大,则分割

 

    2. 找到可满足空闲分区且但分配后剩余空间(最小碎片化)比较小,则一起分配

 

    3. 找不到可满足需要的空闲分区但空闲分区之和能满足需要,则采用内存紧缩技术,进行空闲分区的合并,然后再分配

 

    4. 在成功分配内存后,应保持空闲分区按照BF算法有序排列

 

    5. 分配成功则返回1,否则返回-1
 
  • 其他算法的小结与比较:
  • 最差匹配WF:
    •   策略:最差匹配则与最优匹配相反,它尝试找最大的空闲块,分割并满足需求后,将剩余的块(很大)加入空闲列表。
    •       表现:最差匹配需要遍历整个空闲列表,它的表现非常差,导致过量的碎片,同时还具有很大的开销。
  • 首次匹配FF:
    •   策略:找到第一个足够大的块,将请求的空间返给用户。同样,剩余的空闲空间留给后续请求。
    •       表现:首次匹配有速度优势,但是低地址部分不断被划分,留下许多难以利用、很小的空闲区,而每次查找又都从低地址部分开始,会增加查找的开销。

 

四、内存释放算法

  • 思路:进程终止时,要做的两部分内容:更新分区表,并释放结点。
  • 更新分区表:释放结点:调用函数找到该结点,释放即可。
    • 将新释放的结点插入到空闲分区链的末尾。
    • BF排列空闲链表
    • 合并相邻的空闲分区
    • 利用BF再次排序
  • 源码:
 1 //释放内存
 2 int free_mem(struct allocated_block *ab)
 3 {
 4     struct free_block_type *fbt,*pre,*work;
 5     fbt = (free_block_type *)malloc(sizeof(free_block_type));
 6     if(!fbt) return -1;
 7     //分配空闲分区表的中的一个节点  每一次选择末尾入,并且完成之后查看当前算法,重新整理链表
 8     fbt->size = ab->size;
 9     fbt->start_addr = ab->start_addr;
10 
11     //插至末尾
12     work = free_block;
13     if(work == NULL){
14         free_block = fbt;
15         fbt->next == NULL;
16     }else{
17         while(work ->next != NULL){
18             work = work->next;
19         }
20         fbt->next = work->next;
21         work->next = fbt;
22     }
23     //BF排序
24     rearrange_BF();
25 
26     //合并分区
27     pre = free_block;
28     while(pre->next){
29         work = pre->next;
30         if(pre->start_addr + pre->size == work->start_addr ){
31             pre->size = pre->size + work->size;
32             pre->next = work->next;
33             free(work);
34             continue;
35         }else{
36             pre = pre->next;
37         }
38     }
39 
40     //BF排序
41     rearrange_BF();
42     return 1;
43 }
44 
45 //释放要杀死进程的节点
46 int dispose(struct allocated_block *ab)
47 {
48     struct allocated_block *p;
49     //找到该结点
50     for (p = allocated_block_head; p && p->next != ab; p = p->next)
51         ;
52     p->next = ab->next;
53     free(ab);
54     return 1;
55 }
56 
57 //杀死进程
58 void kill_process()
59 {
60     struct allocated_block *ab;
61     int pid;
62     printf("释放内存, 输入pid=");
63     scanf("%d", &pid);
64     getchar();
65     ab = find_process(pid); //找到pid对应的结点
66     if (ab != NULL)
67     {
68         free_mem(ab); //更新分区表
69         dispose(ab);  //释放结点
70     }
71 }

 

五、运行结果

  • 产生随机测试数据:利用随机数随机生成大小,进行进程的创建。
 1 //创建一个新的进程
 2 int new_process()
 3 {
 4     struct allocated_block *ab;
 5     int size;
 6     int ret;
 7     ab = (struct allocated_block *)malloc(sizeof(struct allocated_block));
 8     if (!ab)
 9         exit(-5);
10     ab->next = NULL;
11     pid++;
12     //进程取名
13     sprintf(ab->process_name, "进程-%02d", pid%3+1);
14     ab->pid = pid;
15 
16     //随机分配空间
17     srand((int)time(0));    //产生随机种子
18     size=rand()%(mem_size/10);
19     if (size > 0)
20         ab->size = size;
21     printf("进程%s:已随机分配大小:%d", ab->process_name,ab->size);
22 
23     ret = allocate_mem(ab); //从空闲区分配内存,ret==1表示分配ok
24 
25     /*如果此时allocated_block_head尚未赋值,则赋值*/
26     if ((ret == 1) && (allocated_block_head->next == NULL))
27     {
28         allocated_block_head->next = ab;
29         return 1;
30     }
31     /*分配成功,将该已分配块的描述插入已分配链表*/
32     else if (ret == 1)
33     {
34         ab->next = allocated_block_head->next;
35         allocated_block_head->next = ab;
36         return 2;
37     }
38     else if (ret == -1)
39     {
40         /*分配不成功*/
41         printf("分配失败\n");
42         free(ab);
43         return -1;
44     }
45     return 3;
46 }
  • 运行结果:

 

 

 

 

 

 

  • 选取4组结果分析:

第一次创建PID:1,从地址0处开始,分配了22个大小的空间。分配后空闲内存从地址22开始,大小为1002。

第二次创建PID:2,从地址22开始,分配了11个大小的空间。分配后空闲内存从地址33开始,大小为991。

第三次释放PID1,空闲内存获得了从0开始大小为22的空间。

 第四次创建了PID:3,从地址33开始,分配了大小为80的空间。同样的空闲内存由原来33开始的991大小空间变成了113开始的911大小空间。

 

posted @ 2020-05-17 11:23  韵韵韵  阅读(396)  评论(0编辑  收藏  举报