如何用Valgrind工具有效检测和排查内存问题
最编程
2024-07-20 12:35:45
...
导读
Valgrind 最为开发者熟知和广泛使用的工具莫过于 Memcheck,它是检查 c/c++ 程序内存错误的神器,报告结果非常之精准。
本文主要分享作者在使用该神器解决内存问题的过程中积累的一些实战经验,希望帮助你快速定位问题甚至在编码阶段就规避这些问题。
Memcheck 可以检查哪些内存错误?
Memcheck 可以检查 c/c++ 程序中常见的以下问题:
- 内存泄漏,包括进程运行过程中的泄漏和进程结束前的泄漏。
- 访问不应该访问的内存,即内存非法读写。
- 变量未初始化,即使用未定义的值。
- 不正确的释放堆内存,比如 double free 或者
malloc/new/new[]
与free/delete/delete[]
不匹配。 - 内存块重叠,比如使用
memcpy
函数时源地址和目标地址发生重叠。 - 向内存分配函数的
size
参数传递非法值(fishy value),比如,负值。
其中,问题 1 中的内存泄漏一般是比较好定位与解决的,但是作者在实际项目开发中遇到过 still reachable
错误掩盖 definitely lost
错误的情况,这就加大了定位内存泄漏点的难度。问题 2 和 3 属于出现频率较高的一类内存错误,它们往往会引发程序 crash,这类错误必须要高度重视,且一定要解决。问题 4、5、6 也属于典型的内存错误,使用 Memcheck 可以很快的定位并解决这些问题。
对于 c/c++ 开发者来说,如果不能及时发现并消除这些内存隐患,那么,偶尔的 crash、难以诊断的 coredump 将会是挥之不去的噩梦。而且这些内存问题可能很难通过一己之力去定位,尤其是当程序的代码量庞大、逻辑抽象且复杂的时候,更是会让人焦头烂额。此时,Memcheck 就是辅助我们解决这堆内存问题的神器。
使用 Memcheck 解决问题的原则
当使用 Memcheck 工具输出程序的内存检查报告后,我们该如何着手去解决报告中的问题呢?作者根据长期使用积累的经验,总结了如下四个原则。
原则 1,内存非法读写错误一定要解决
这类错误在检查报告中以 Invalid read/write of size x
的格式输出。这类错误出现的场景主要有三种:
- 动态分配的内存已经被释放,然而开发者还在对这块无效的内存进行读写操作。
比如悬挂指针,即基类指针指向的子对象已经被释放,然而却继续使用该基类指针调用其方法。
- 动态分配的内存未被释放,然而访问这块内存发生越界。
比如拷贝字符串时忘记结尾的字符