操作系统原理——实验五:内存管理_Debug

本实验的问题在于通过测试,具体的Bug,具体分析,以下仅给出算法与几点建议。
1.void *malloc(size_t size)

  • 功能:
  • 分配大小为size字节的内存块,并返回块起始地址
  • 如果size是0,返回NULL
  • 算法:
  • 如果size为0,返回NULL
  • 根据首次原则找到符合条件的select指针,(select->state == FREE) && ((select->size - sizeof(struct chunk)) >= size)
  • 剩余空间不足,返回NULL
  • 如果减去参数size+sizeof(struct chunk),剩余空间大于sizeof(struct chunk),创建新的chunk,new
    (1)初始化new
    (2)修改select
  • 修改select->state=USED;
  • 返回ptr=((uint8_t *)select)+sizeof(struct chunk);

2.void free(void *ptr)

  • 功能:
  • 释放ptr指向的内存块
  • 如果ptr是NULL,直接返回
  • 提示:
  • 根据ptr得到chunk:
  • struct trunk *achunk=(struct chunk *)(((uint8_t *)ptr)-sizeof(struct chunk));
  • 要求:
  • 必须验证ptr的有效性:判断achunk->signature是否等于“OSEX”
  • 必须合并相邻的空闲块
  • 算法:
  • 如果ptr是NULL,直接返回
  • 根据ptr得到chunk地址struct chunk* achunk=(struct chunk *)(((uint8_t *)ptr)-sizeof(struct chunk));
  • 检验achunk->signature是否等于“OSEX”,相等时,strncmp(achunk->signature, “OSEX”,4)==0
  • 合并相邻的空闲内存块,检查achunk前后是否为FREE:如果为FREE,合并chunk
    (1)如果achunk不是最后一个chunk,检查achunk后一个内存块
    (2)如果achunk不是chunk_head,检查achunk的前一个内存块
  • 修改achunk->state=FREE

3.void *calloc(size_t num, size_t size)

  • 功能:
  • 为num个元素的数组分配内存,每个元素占size字节
  • 把分配的内存初始化成0
  • 算法:
  • 如果size或num为0,返回NULL
  • 根据首次原则找到符合条件的select指针,(select->state == FREE) && ((select->size - sizeof(struct chunk)) >= num*size)
  • 剩余空间不足,返回NULL
  • 如果减去参数size+sizeof(struct chunk),剩余空间大于sizeof(struct chunk),创建新的chunk,new
    (1)初始化new
    (2)修改select
  • 修改select->state=USED;
  • 初始化分配的内存为0,memset(ptr, 0, num * size);
  • 返回ptr = ((uint8_t *)select) + sizeof(struct chunk);

4.void *realloc(void *oldptr, size_t size)

  • 功能:
  • 重新分配oldptr指向的内存块,新内存块有size字节
  • -如果oldptr是NULL,该函数等价于malloc(size)
  • -如果size是0,该函数等价于free(oldptr)
  • 把旧内存块的内容复制到新内存块
  • -如果新内存块比较小,只复制旧内存块的前面部分
  • -如果新内存块比较大,复制整个旧内存块,而且不用初始化多出来的那部分
  • 如果新内存块还在原来的地址oldptr,返回oldptr;否则返回新地址
  • 要求:
  • 必须验证oldptr的有效性
  • 必须合并相邻的空闲块
  • 算法:
  • 如果oldptr是NULL,该函数等价于malloc(size)
  • 如果size是0,该函数等价于free(oldptr),但是要注意返回NULL
  • 根据oldptr得到chunk地址struct chunk *achunk=(struct chunk *)(((uint8_t *)oldptr)-sizeof(struct chunk));
  • 检验achunk->signature是否等于“OSEX”,相等时,strncmp(achunk->signature, “OSEX”,4)==0
  • 修改achunk->state=FREE;
  • 合并相邻的空闲内存块,检查achunk前后是否为FREE:如果为FREE,合并chunk
    (1)如果achunk不是最后一个chunk,检查achunk后一个内存块
    (2)如果achunk不是chunk_head,检查achunk的前一个内存块
  • 根据首次原则找到符合条件的select指针,(select->state == FREE) && ((select->size - sizeof(struct chunk)) >= size)
  • 剩余空间不足,返回NULL
  • 如果减去参数size+sizeof(struct chunk),剩余空间大于sizeof(struct chunk),创建新的chunk,new
    (1)初始化new
    (2)修改select
  • 修改select->state=USED;
  • 计算ptr= ((uint8_t *)select) + sizeof(struct chunk);
  • 比较ptr和oldptr,相等则直接返回
  • 如果新内存块比较小,只复制旧内存块的前面部分,strncpy((char *)ptr, (char *)oldptr, select->size - sizeof(struct chunk));
  • 如果新内存块比较大,复制整个旧内存块,而且不用初始化多出来的那部分,strncpy((char *)ptr, (char *)oldptr, achunk->size - sizeof(struct chunk));
  • 返回ptr

温馨提示:

  1. chunk链表为临界区,在读与写之前需要利用信号量进行保护
  2. 地址往后增加,在将select内存块分裂成两个chunk时,需要考虑new的值应该是select+sizeof(struct chunk)+size;
  3. 创建新的chunk时,需要考虑select内存块的剩余空间是否可以允许创建;
  4. 由于在读chunk链表时,进行了保护,sem_wait()的位置在函数的前面,注意每一次return之前都要调用sem_signal(),避免卡死;
  5. 合并空闲块时,注意achunk位于链表首部或尾部的情况是否考虑;
  6. 如果遇到“死机”(“卡住不动”),考虑在sem.c文件的sem_wait()和sem_signal()函数里面添加printk()来打印当前value值,以便观测第几次函数调用导致“死机”,进行后续的Debug工作;
  7. Debug的时候可以考虑注释掉一些测试,以便观测具体在哪个函数出问题,比如说为了区分Bug位于malloc还是free,可以将无法通过的测试之前的测试全部注释,如果还是无法通过,那么推断Bug很可能在malloc处,此方法可以结合上述的打印信号量当前value一起使用,效果更佳。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值