简单的malloc分配器设计
1、隐式空闲链表结构
隐式空闲链表由N多个块组成,一个块由一个字的头部、有效载荷(只包括已分配的块),以及可能的一些额外的填充(为了保证内存字节对齐而需要的填充)和尾部组成。头部大小为一个字,即四个字节,在强加双字对齐的约束之后,块大小总是8的倍数,所以用高29位来表示存储块大小,剩余3位中利用最低位来表示块是否已分配;尾部和头部的内容一样,加入尾部是为了分配器可以判断出一个块的起始位置和状态
2、空闲块组织
堆空间就是一个隐式空闲链表,从低地址向高地址生长,第一个和最后一个8字节标记为已分配,以确定堆的大小
3、放置
首次适配法:也就是遍历链表的时候找到的一个符合所需要求的块就立即分配,优点是可以通过每次找到合适的块就立即分配的方法来将大块儿的空闲块留在链表的后面,但是会在链表的前面块留下许多小碎片
下一次适配法:也是找到一个合适块的时候就分配,但不是像首次适配法那样每次都从链表头部开始搜索,而是从上一次分配的结束的地方开始分配,这样可以跨过前部分的小碎片,加快搜索速度,但是很明显会错过一些更合适的块,这样就导致了存储器利用率的下降
最佳适配法:检查每个空闲块,寻找合适的最小空闲块进行分配
4、分割
要求双字对齐的时候,如果不允许分配0字节,那么最小分配字节应该是16字节(头部4字节+分配1字节+尾部4字节+填充7字节),若剩一个32字节的空闲块,但是我们只需要一个字节,那么就可以把这32个字节的低16字节和高16字节分割出来
5、合并
继续上面的假设,如果我们把malloc的一个字节free之后,应该把释放出来的16字节和原来32字节中另外的16字节合并起来,下面讨论带边界标记(头部尾部)的合并
1)前后块都已分配:直接释放当前块即可
2)前块分配后块空闲:和后块合并
3)前块空闲后块分配:和前块合并
4)前后块都已空闲:和前后块合并
6、堆空间申请
通过sbrk函数,增加brk的值来分配堆空间
7、简单分配器的C语言实现
见代码分享