深入理解计算机系统实验日志(四)——MallocLab Debug实验记录

说明:本日志主要用来记录自己的debug过程,对于malloc这种需要对地址空间进行直接分配和管理的实验,必须要debug才能找出错误在哪。一开始真是不知道从何下手,通过自己慢慢摸索,逐渐找到了方法,对gdb的使用也越来越熟练,提高了自己的debug能力,也希望给同样不知道如何开始debug的小白一点参考。

注意:
先根据课本上给的范例实现隐式空闲链表,并且好好理解。
一跑有87分还不错哦
在这里插入图片描述

(一)显示空闲链表

在隐式空闲链表的基础上,我们实现显示空闲链表。
以下是设计图:
在这里插入图片描述

写完初版代码,一运行,毋庸置疑:Segmentation fault!

注意:

  1. 每次修改完一定要重新编译:make
  2. 使用gdb进行调试的时候一定要先修改“Makefile”文件中的“CFLAGS”在参数最后加“-g”,gcc编译的时候要加入-g参数才能使用gdb调试,否则就会报以下错误。

在这里插入图片描述
再次运行gdb,我们就可以看到错误发生时所在的源代码了。
在这里插入图片描述
但是有个问题是,通过backtrace我们可以看到栈中的内容,但是我们不知道在这之前都运行了哪些函数,在思考这个问题并且无从下手很久之后。
……TWO THOUSAND YEARS LATER……
PRINTF大法来了:在所有函数的开头都输出函数名,涉及指针和SIZE大小相关的也进行输出,在此基础上,配合上gdb,一切都开始变得行云流水了起来。
运行结果如下:
在这里插入图片描述

DEBUG1:

发现没有调用insert_to_freelist函数
出现了新的问题,为什么没有用还能找到4024的空间?

DEBUG2:

在这里插入图片描述

划重点:
heap_listp: 0xf69ed020
root: 0xf69ed014
*** extend_heap(4096)bp:0xf69ed028
*** coalesce(bp=0xf69ed028)no need coalesce
*** insert_to_freelist(bp=0xf69ed028,size=4096) //插入root的时候有错误,观察insert_to_freelist函数,输出root和bp
*** mm_malloc(size=2040)
*** findfit(size=2048)
找到0xf69ed018

疑点1.
“*** findfit(size=2048)
找到0xf69ed018”

为什么找到的不是root: 0xf69ed028?
检查0xf69ed018是否是正确的空闲块,看其大小csize很大,所以root肯定有问题。
在这里插入图片描述
说明在插入root的时候就有错误,观察insert_to_freelist函数(打断点:break insert_to_freelist),输出root和bp
在这里插入图片描述
果然root值不对,没有被赋值

bp指针初始化为root肯定是错的,再看看findfit的时候遍历查找空闲块的时候bp指针的变化。
在这里插入图片描述
不幸的是查看不了:$1 = < optimized out >

参考word文档——解决
Unfortunately, the variable is still optimized out! While -Og ensures that the information that GDB shows is correct (compared to -O3), there will still be some variables that are optimized out. This makes sense if you think about how assembly works: the value of many variables are often discarded, unless there is a reason to save them. To fix this, go into the Makefile and change the debug optimization level to “COPT_DBG = -O0”. The resulting code is very inefficient, but it should preserve all local variables.
修改Makefile文件中的“CFLAGS”设置,将参数改为“-O0”。

bp=root是root变量本身存储的地址
而不是root指向的地址
在这里插入图片描述

仔细检查insert_to_freelist函数
“PUT_PTR(root,bp);”语句没有问题
在此不知何时突然恍然大悟,如果让bp=root的话,那么bp指向的是root指针本身存储的地址,而不是保存的值,正确的方式应该是bp=GET(root),才能获取到root保存的值!!!

检查所有的指针引用,有很多地方需要更正:
In function ‘insert_to_freelist’: GET(root)
In function ‘relink’: GET(PRED(bp))——不是获取PRED(bp),而是前面连接的空闲块的所在地址
In function ‘find_fit’: bp=GET(root)

DEBUG3:

在这里插入图片描述
运行gdb看看是在哪一步出了问题,好吧这里应该是把“bp”放到“root”而不是“oldroot”//更改太着急,不仔细啊!
在这里插入图片描述

DEBUG4:

依然报错,这次看看又是什么问题:
在这里插入图片描述

*** relink(bp=0xf6993028)链接后(前后连上检验-是否指向同一块)0x4 0x0一眼就可以看出来relink函数出了问题0x4 0x0
看了代码发现这里应该是printf输出的问题,与代码本身无关。
在输出中也加上GET:printf(“链接后(前后连上检验-是否指向同一块)0x%x 0x%x\n”,GET(SUCC(prev_node)),GET(PRED(next_node)));
——重来
在这里插入图片描述
又报错了……这次是输出语句的问题,跟代码无关,因为第一次prev_node和next_node都为NULL,经过前面检验,relink的前后连接是没有问题的,因此这里直接删除printf语句

好这一次让我们专注函数的运行来观察一下什么地方出错了
在这里插入图片描述
经过一番分析,发生错误的时候,freelist中仅有一块1992字节大小的空闲块,位于0xf69ed860。而此时要分配4080大小的空闲块,错误的关键来了,在findfit中竟然找到了,而此时执行place函数肯定就会报错了。那么明明空间不够的情况下,findfit为什么会找到呢?
gdb调试,打断点在find_fit
在这里插入图片描述
为什么此时第一个空闲块大小bpsize这么大啊
输出bp,发现bp还是最开始分配的空闲块指针,root也是,那么此时的root按道理应该存放的是0xf69ed860位置的值
在这里插入图片描述
wait wait报错的不是第一个find_fit,继续吧,被自己蠢哭了,但是根据刚才的分析这里也有点问题,等下如果还报错再回来看看。
在这里插入图片描述
找出错误,在修改find_fit函数时漏加了一个GET……
改正:bp=GET(SUCC(bp))

DEBUG5:

在这里插入图片描述
在这里插入图片描述
仅有空闲块1992大小不够,额外申请8192的空间,然后发现和前面一块空闲块的地址是相连的,进入“else if(!prev_alloc&&next_alloc)”条件判断后的then语句。那么就要relink后一块的地址,而0xf69ed860是第一个空闲块的地址

发现代码逻辑错误:
修改前:

bp=PREV_BLKP(bp);
relink(PREV_BLKP(bp));

修改后:

relink(PREV_BLKP(bp));
bp=PREV_BLKP(bp);
DEBUG6:

在这里插入图片描述
又报错了,这次问题好像更复杂了,先检查一下是否还有跟刚刚一样的错误,果然有!
在最后一个合并前后块的代码中也出现了逻辑错误
修改前:

bp=PREV_BLKP(bp);
relink(PREV_BLKP(bp));
relink(NEXT_BLKP(bp));

修改后:

relink(PREV_BLKP(bp));
relink(NEXT_BLKP(bp));
bp=PREV_BLKP(bp);

成功了成功了!

注意在这里编译的时候出现了warning,但我们就是利用存储的整数值来获取指针,因此没有问题
在这里插入图片描述

但是只有54分……我裂开了……发生甚莫事了……还不如隐式链表……
在这里插入图片描述
突然想起来有一大堆printf语句,会影响程序性能,于是删除之后再试试

哦豁不错,这才是它真正的实力👍
在这里插入图片描述
当然啦,我们必须要进一步优化我们滴代码啦~
众所周知,分离空闲链表+Best Fit才是坠吊的,那我们来试试。(本来是个正经的实验记录,画风好像逐渐走偏)

(二)分离空闲链表

在隐式空闲链表的基础上起草宏伟蓝图:
在这里插入图片描述

DEBUG1:

PRINTF大法好,先了解程序在干什么
在这里插入图片描述
分配4096->拿走2048->拿走2048->释放2048->拿走56->还剩1992->拿走4072->扩展8192->合并+1992=10184->拿走4080->还剩6104->释放刚拿走的4080->和后一块合并

*** mm_free(bp=0xf69ed880,size=4080)
*** coalesce(bp=0xf69ed880)
*** relink(bp=0xf69f0048,size=0)
fitsize_root:第0块
合并后一块,bp不变

发现关键语句错误:relink(bp=0xf69f0048,size=0)
后一块6104的地址是0xf69ee870,因此正确的输出应该是relink(bp=0xf69ee870,size=6104)
所以是relink(NEXT_BLKP(bp));中的NEXT_BLKP(bp)错了

又是coalesce函数中relink的顺序错了……可恶
但是为什么在刚刚的隐式链表的实现中没有报错,这里很奇怪

else if(prev_alloc&&!next_alloc)的then语句:
修改前:

PUT(HDRP(bp),PACK(size,0));
PUT(FTRP(bp),PACK(size,0));
relink(NEXT_BLKP(bp));

修改后:

relink(NEXT_BLKP(bp));
PUT(HDRP(bp),PACK(size,0));
PUT(FTRP(bp),PACK(size,0));
DEBUG2:

这次检查了前面的分配没有任何问题,但是在插入空闲块2048的时候又报错,出错在while循环语句
在这里插入图片描述
经过一番分析,当前只有第九块中有一个空闲块(bp=0xf6915870,size=6104)
(bp=0xf6914048,size=2048)插入第八条链表,p应该为null,但是其第一块地址为0xf69ed880,0xf69ed880是之前块所在地址,说明1992大小的空闲块在relink的时候出错了,第八条链表的表头没有重置为NULL
在这里插入图片描述
relink的时候发生在被后面分配的8192空闲块合并。果然啊,又是在改变size的时候才把指针头塞给relink重置,因此就重置到第九条链表去了,如下所示:
insert_to_freelist(bp=0xf69ed880,size=10184)
fitsize_root:第9块

正确写法:

else{
        size+=GET_SIZE(HDRP(PREV_BLKP(bp)))+GET_SIZE(FTRP(NEXT_BLKP(bp)));
        relink(PREV_BLKP(bp));
        relink(NEXT_BLKP(bp));
        PUT(HDRP(PREV_BLKP(bp)),PACK(size,0));
        PUT(FTRP(NEXT_BLKP(bp)),PACK(size,0));
        bp=PREV_BLKP(bp);
    }

运行结果,很奇怪的是,忙活了那么久,没有提升!!!
在这里插入图片描述
最后三种实现方式的运行成绩竟然一模一样……
不死心地试了一下优化,但是运行成绩稳如泰山、无动于衷,本实验日志主要记录debug过程,因此这里也不多作赘述了,反正都是无用功。
总结一句:“昨天我还大呼不会debug,今天我就爱上gdb。”

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值