malloc lab总结

11月份断断续续的把CSAPP的malloc lab给做了。其中碰到挺多麻烦,但也学到了很多分析问题的方法。做一个总结。

分配器的性能分为两方面:吞吐率和内存利用率。吞吐率指的是在分配和释放空间过程的平均时间,内存利用率是最小化碎片。因为分配的空间大小需要8或者16字节对齐(根据自己的分配器实现方法而定),所以在分配过程中肯定会产生内部或者外部碎片。

接下来就是分配器的实现方式了。因为在分配heap过程中用到了mmap,所以在操作这片内存空间的存储得用到大量的宏操作来方便程序的编写。

整个分配器包括3个部分,初始化,即分配出一小段heap空间,其中包括特殊的头和尾块。在实际的测试当中,我发现512的大小能够最大化内存利用率(最初我直接用的1M,结果一直内存利用率为0,试了各种分配方式,最后还是某个大神指点才发现,看来我对内存的数字还没有一个敏感的认识。一个程序怎么都不可能直接把heap提到1M的空间啊,太浪费了!)。特殊块的作用也是简化程序代码的复杂度。

然后就是malloc的分配空间方式了。分配块的结构有2种,隐式链表和显式链表,隐式链表指在分配块的头部和尾部有4个字节的标志位,1个标志位是32位,其中前29位用来表示当前块的大小,后3位来表示块是否已分配(其中一个优化方式是3个位分别表示该块的前一块,当前块,后一块是否已分配。而隐式链表包含显式链表的属性,同时在未分配的块当中有8字节用来表示前一个空闲块的指针和后一个空闲块的指针。2种结构的最小块都是16字节,而且是8字节对齐。很显然,显式链表比隐式链表优越,因为在寻找空闲块时,它跳过了已分配块,节省了大量的时间。

然后我们遇到的另外一个问题就是如何查找合适的空闲块。最简单的方法就是从头遍历list,复杂度为O(n)。我们也需要考虑内存的利用率,有三种算法,首次适配,下次适配和最佳适配,最佳适配是查找合适的大小,这种方式碎片最小,利用率最高。而因为显式链表的块是随机分配的,随机性很大,所以可以按照空闲块的大小来分配分离不同的链表。这种按块大小分离的管理链表方式,相对于普通的空闲链表,查找空闲块的速度可以有大幅的提升。放置过程有一个优化方式是在查找到一个较大的空闲块中,我们把该块的尾部的块分配,这样就可以减少不必要的链表指针操作,因为空闲块的指针存储在有效负载的前8个字节。

而free需要注意的问题是释放空闲块后,是否需要合并。这就产生了2种方式,一种是释放块后立刻合并,另外一种是选择适当的时机合并。速度和空间总是相斥的,我采用的方法是释放块后立刻合并,也可以在释放N次后遍历所有空闲块合并一次。因为要保证吞吐率和内存利用率的平衡,所以具体的优化得经过大量的测试来判断。


你可能感兴趣的:(ICS学习笔记)