C++调试经验小结

工作稍微有一段时间了,实践过程中遇到了一些debug方面的问题。涉及到的细节时间长了难免会有遗忘,因此在这里记录下来,也希望能对其他正在和bug做苦苦斗争的同学能有所帮助。

  • valgrind
    这工具是Linux下面检查内存错误的大杀器,主要用来程序在内存操作上的问题,包括越界读写,内存泄露等。具体工作原理可以参考这里
    valgrind最大的问题是,它是在运行时检查程序的内存问题的,会让程序的运行速度降低20倍左右。对于玩具程序而言这不是什么问题,但是如果你的程序初始化就需要十分钟的话,用它来检查问题的可操作性就很弱了。
    另外一个问题是,valgrind不能设置检查的范围(也可能是我不会使)。如果你的程序需要链接各种外部库,那么很可能你需要检查的错误信息会淹没在外部库的出错信息里面。
  • gdb调试
    用gdb调试程序应该是每一个linux下c++程序员的必修课,不过对于内存越界仍然有一些trick可以用。
    对于最理想的越界情况,类的成员变量或者堆上的数据被破坏导致程序出错,这时候只需要定位到出错时候出问题的数据内存地址,再用watch *0x12345这样的方式设置watch断点,就可以断到导致越界的凶手处了。
    不过内存越界往往会破坏一些奇怪的地方,导致gdb看上起根本没法儿调试。比如有时候越界写可能导致c++对象的虚函数表被破坏,这种情况会导致出错时候最后一层函数的调用堆栈变成问号。因为虚函数表其实就是保存在对象开头处的内存指针,只需要针对出错对象的内存地址使用watch断点就可以找到犯罪现场了。
  • 静态代码检查
    相比较于valgrind, gdb这些费时费力亡羊补牢的方式,静态代码检查工具可能会省掉很多不必要的调试时间。最常用的可能就是cppcheck这个工具了,它会检查数组越界、内存泄露、资源未释放等等问题。
  • 性能调优
    可能很多人会使用log日志等方式来自己统计性能。但是这么做统计的粒度取决于日志输出的频率,同时还需要使用宏或者其他方式针对release和debug环境做不同的处理。目前看来最好用的方案是google的性能统计工具gperf tools。这个工具的优点在于可以进行函数级别的性能统计,对程序本身的性能影响可控(取决于你需要的统计频率,用户可以针对统计精度和性能影响之间做权衡),并且可以不用修改程序源代码。
    gperf tools的使用本身没有什么好说的,需要注意的一点是,使用官方推荐的libunwind(一个gperf tools的依赖库)版本会导致程序崩溃,我在使用最新的git上的版本以后没有遇到问题。
    对于需要统计性能的程序,需要在编译时候使用-g参数将函数符号编译进去,否则最终统计出来的性能数据中只能看到内存地址,看不到函数名。
    最后一个需要注意的地方就是,如果被统计的程序一直处于挂起状态是没法儿统计到数据的。gperf tools需要程序一直占用cpu,然后才会进行断点统计。

发表评论

电子邮件地址不会被公开。 必填项已用*标注