malloclab 实验详解(动态分配器如何设计)

本文详述了CSAPP中的动态内存分配器原理,包括首次适配、最佳适配和下一次适配等策略,并介绍了如何通过实验代码实现这些算法。文章探讨了内存碎片的类型、合并块的方法以及衡量分配器性能的指标,如空间利用率和搜索效率。最后,提到了分离适配优化和realloc的改进方法,以及实验中遇到的问题和解决方案。
摘要由CSDN通过智能技术生成

本文主要针对CSAPP中的动态内存分配器做一个讲解,在讲解书上的各种分配器如何设计的同时,用实验的实际代码来实现这些算法。
首先,先贴上书本配套实验的地址:http://csapp.cs.cmu.edu/public/labs.html
备注:这个实验地址并没有给出实际的traces里面的测试,
相关的测试以及最终的答案可以从我的github上下载:https://github.com/HBKO/malloclab
首先,要理解动态分配器是个什么东西?简单来说,动态分配器就是我们平时在C语言上用的malloc和free,realloc,通过分配堆上的内存给程序,我们通过向堆申请一块连续的内存,然后将堆中连续的内存按malloc所需要的块来分配,不够了,就继续向堆申请新的内存,也就是扩展堆,这里设定,堆顶指针想上伸展(堆的大小变大),不能向下增长(虽然,sbrk函数也可以让指针想下伸展),以下是堆的一些说明:
这里写图片描述
那么,对于如何管理这个堆,主要有这么几步操作:
一.find_fit:找到一个合适的块,分配出去,这里寻找块的方法也有以下几种(这里指申请需要的空间为needsize):
(1).首次适配:就是在搜索整个堆或者空闲链表的时候,只要找到一个比needsize就直接申请出去。(优点:速度快。缺点:不一定找到空间最合适的块,空间利用率降低(但是利用分离适配的方法可以让首次适配的空间利用率也提升))
(2).最佳适配:在搜索的时候,找到一个

needsize<=size && min(size-needsize)

的块。(优点:能找到最合适的块,空间利用率高。缺点:对于大的空闲块搜索效率低(因为经常都是把小的空闲块安插在链表前))
(3).下一次适配:下一次适配和首次适配很类似,首次适配是从空闲链表头开始寻找,下一次适配是从上一次分配的地方开始搜索。但有些研究表明,下一次适配比首次适配的效率更快,但空间利用率更低。所以我们的实验中一般采用首次适配和最佳适配。
二.分割块(放置块):在申请一个块的时候,如果这个块的大小远大于我们的需求,我们就要分割块(这个分割块的界线在于最小块的大小是多少),分割出来的块标为空闲的,放入空闲链表中(但是在针对realloc优化的时候发现,很多时候在realloc不分割的时候空间利用率更好,可能是针对特定的case才有这种情况)。
三.合并块:我们想要降低空间利用率,就要降低假碎片的出现,这里就要介绍一下什么是内存分配产生的碎片了。
(1)内部碎片:内部碎片的产生是在一个已分配块比有效载荷大的时候,就如同如下结构:
这里写图片描述
一个空闲块必须得要有空间存放头部和脚部,这里头部和脚部就是内部碎片,减少内部碎片的办法就要减少这样每个堆块必须分配的内存。
(2)外部碎片:外部碎片就是当空闲存储器合计起来足够满足一个malloc请求,但是却无法申请的时候。如下图所示:
这里写图片描述
在图片这个情况,如果我申请的块大小为20,那么就没法申请,即使现在空闲块的总和是8+16=24,但还是伸展堆的大小,伸展出新的块出来。所以,外部碎片也可以说是最棘手的一种碎片,因为无法预估后来申请块是大还是小块,如果一大一小的申请。并且,只释放小块,这样就很容易产生外部碎片。
为了降少这些外部碎片,我们就需要进行空闲块的合并。但是,如果我们采用单向链表的形式,在每次合并的时候,就要遍历整个链表进行合并。当然啦,我们采用延迟合并的策略,即得到我们每次malloc需要新的空间的时候再进行合并,在需要的时候再进行合并。从根本上减少合并的次数来节约时间。但是,这里Knuth提出了一种标记块的方法(我认为是相当巧妙的一种方法),利用头部和脚部来存储块的大小以及是否被申请的信息,头部和尾部的信息都一样,就如图9-39的结果,可以就可通过一个块,访问前一个块和后一个块,使得合并达到常数时间,具体获取前后块的代码如下图所示:

#define HDRP(bp) ((char *)(bp)-WSIZE)
#define FTRP(bp) ((char *)(bp)+ GET_SIZE(HDRP(bp))-DSIZE)
#define NEXT_BLKP(bp) ((char *)(bp)+GET_SIZE(((char *)(bp)-WSIZE)))
#define PREV_BLKP(bp) ((char *)(bp)-GET_SIZE(((char *)(bp)-DSIZE)))

合并的四种情况无非就是:1.前后都忙碌。2.前忙碌,后空闲。3.前空闲,后忙碌。4.前后都空闲,如下图所示:
这里写图片描述
好了,我们要对这个内存分配器所做的操作都说完了,就是说我们的基本零件有了。
但是,我们如果想衡量一下我们所做的这个内存分配器需要那些指标呢?
1. 空间利用率:

Uk=k
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值