完整代码见:CSAPP/malloclab-handout at main · SnowLegend-star/CSAPP (github.com)
Malloc Lab
按照惯例,我先是上来就把mm.c编译了一番,结果产生如下报错。搜索过后看样子应该是编译器的版本不匹配,得建立条软链接。
经过多番尝试,最后得到正确的链接形式是
“ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/asm”
隐式空闲链表
这方法就是把书上的那几个函数搬过来就行,唯一需要自己动手的是realloc()函数。但是书上的那一大块宏定义属实是看得我两眼发昏。特别是NEXT_BLKP(bp)和PREV_BLKP(bp)这两个定义,直接把我绕晕了。
后来仔细分析了一番,发现最根本的原因是我把隐式空闲链表的头/尾块和内存块的头/尾部弄混了,导致每次分析堆内块的4byte头/尾部分的时候就会不自觉想到链表的头/尾部分。明白两者的不同之后,接下来分析宏定义等就显得直观明了了。
在排查bug的时候,没有实现把指针ptr定位到堆块的头部再进行指针操作确实是害苦了我。刚才就是一个困扰我很久的问题。
说完指针定位到头部的问题后,再来谈谈void *mm_realloc(void *ptr, size_t size)的实现框架。
1、ptr=NULL,size≠0:调用malloc()
2、ptr≠NULL,size=0:调用free()
3、ptr≠NULL,size≠0:调整size为asize
3.1、asize=blocksize_Cur:直接分配
3.2、asize<blocksize_Cur:调用place()把当前块进行分割
3.3、asize>blocksize_Cur:当前块的大小不足以分配
3.3.1、next block空闲,且两个块的大小和blocksize_Sum>aszie:对下一块使用place()
3.3.2、next block已分配,或者两块大小和blocksize_Sum<aszie:调用find_fit()来寻找一个全新的块进行分配,而不考虑当前块和next block
3.3.2.1、find_fit()找到了合适的块:调用place()进行分配
3.3.2.2、find_fit()未找到合适的块:先用extend_heap()来申请新的堆空间,再调用place(),最后把原来块的内容拷贝到新块里面,释放原来块的空间。
最后得到的测试结果如图。
分离空闲链表
对于显式空闲链表,判断节点bp的前驱是否是头结点相当简单,如下
但是对于分离空闲链表来说,就显得比较繁琐了。按照上面的思路,我们得先用一个大循环来遍历24条链表的各个头结点,然后再用上述式子。不如把这个循环遍历做成一个单独的函数,以此来判断前驱是否头结点的问题。
if(isSegList(pred_ptr)){ //如果前驱是头结点
汗流浃背了,代码出了个bug。
然后是调试环节。
我先是一直在那输入“gdb mm”,结果代码在gdb模式下run起来都有问题,让我心生怀疑可能是调试错了文件,最后才发现pdf上写着调试应该是“gdb mdriver”,白忙活一场。由于默认调试的执行文件是“short1-bal.rep”,想要调试其他文件就得改config.h,但是我发现无论怎么修改config.h,都会报下面的错误。这也是浪费最多时间的一部分。