调试方法小结(持续更新)

曾听人说过,开发人员80%的时间花费在环境配置和定位错误上。我现在对此深以为然。

环境配置是新人最花费时间的地方,但随着对环境的熟悉,如果不出大差错,那么花在其上面的时间会迅速减少。但错误定位一直是最让人头痛的地方,由于经验原因,老鸟和菜鸟在定位错误上的能力相差很大。本文记录下了我在错误定位过程中所采用的方法和遇到的问题,一是以备日后查阅,二是与大家分享。由于本人是刚毕业不到一个月的菜鸟,大家有好的方法还望多多指教。


一. 崩溃的调试

崩溃的调试是相对容易定位的,但要找出其崩溃的原因却并非易事,因为崩溃的原因可能与崩溃的位置相距很远,甚至看似风马牛不相及。

1. 定位崩溃地点。最容易的一步,直接在gdb中运行程序,或者看日志信息,很快就能定位到崩溃的函数。

2. 准确定位。在崩溃的函数设置断点,运行到该断点。用bt命令查看并记录调用堆栈。然后用n单步运行,确定崩溃的语句。

3. 寻找崩溃原因。崩溃的直接原因在第1步gdb中会有提示。比如SIGSEGV段错误,运行时崩溃大多是对内存的误操作造成的(是不是?)。所以仔细检查崩溃语句所涉及的变量,看看有没有比较明显的 引用空指针,重复释放内存,引用非法地址等问题。

4. 初步确定了崩溃原因,下一步就是顺藤摸瓜,找出造成该原因的罪魁祸首。这一步首先跟操作有密切关系,一般有3种形式。

a. 每次运行都崩溃

b. 按特定的步骤运行崩溃

c. 偶然性崩溃

情况a最简单,沿着调用堆栈查看,配合调试,一般可以找出源头。情况c最复杂,基本只能靠分析,而很难调试。

情况b需要根据状况分析出可能引起崩溃的操作,检查该操作涉及到的部分,配合调用堆栈来寻找原因。

5. 不用只局限于崩溃的那个类或文件,有时候错误原因比较隐蔽,有可能是相关的文件或类造成的。

特别是如果崩溃的文件是一些底层的文件(如操作系统),这些文件已经反复被验证,几乎不可能存在问题。此时问题最可能出在上层的文件中,是不正确的调用或者销毁,构造等操作导致了程序的崩溃。

此时应该从源头开始排查,只纠结于崩溃的文件是找不出原因的。

我就遇到过一次,程序崩溃在操作系统文件,经过一整天的排查,才发现操作系统文件没问题,我们的应用程序文件也没问题,最终的原因竟然是gtest单元测试文件出的问题。根本原因还是引用了已经释放的内存。

6. 特别注意的地方有:构造与析构,赋值,delete与free,一些对象的生存周期,数组越界等问题。


二、程序异常行为调试

有时候程序仅仅出现异常的行为,不按我们的设计来运行,但是却不会崩溃。此时的难点是从哪里进行调试。

如果你对程序的运行流程了如指掌,那这个难点也就不复存在。但如果你对程序的运行只是一知半解,那就要花费一些时间了。如果你对该问题的背景一无所知,那么这个问题不适合你,最后换一个问题。

我一般的做法是:

首先,确定一个比较重要的函数,该程序一定能够运行到,或者确定一些函数,看程序会运行到哪个。

其次,查看程序运行到断点参数是否正常。若不正常则按调用堆栈向上查看,若正常则通过分析向下走。

这种错误一般都是由于程序走了不正确的分支造成的,在关键的函数单步调试,确定程序在哪儿走了不正确的分支。

根据判别条件来查找走了不正确分支的源头,这个源头可能很长,也可能有多个看似可能的原因。通过分析来找出最可能的原因。

对于任何调试而言,有时候确定位置比较容易,但确定原因却很难。因为这需要丰富的知识作为支撑,高手们往往可以轻松分析出原因,但菜鸟经常似是而非,通过尝试才能知道原因。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值