Memcheck
默认的工具,用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc、free、new、delete的调用都会被捕获。所以,它能检测以下问题:
对未初始化内存的使用;
读/写释放后的内存块;
读/写超出malloc分配的内存块;
读/写不适当的栈中内存块;
内存泄漏,指向一块内存的指针永远丢失;
不正确的malloc/free或new/delete匹配;
memcpy()相关函数中的dst和src指针重叠
valgrind只报告内存泄漏,但没有显示具体代码中泄漏的地方。因此需要使用--leak-check=full
选项启动valgrind。你的程序将比正常的运行慢得多(如20〜30倍),并使用更多的内存。Memcheck会报告关于内存错误,和检测到的泄漏的消息。
Memcheck也报告未初始化值的使用,最常见的消息是Conditional jump or move depends on uninitialised value(s)
。可以难以确定这些错误的根源。尝试使用--track-origins=yes
来获得额外的信息。这使得Memcheck运行得更慢,
Invalid write of size 1 //堆内存越界被查出来
Invalid free() / delete / delete[] //重复释放
Process terminating with default action of signal 11 (SIGSEGV): dumping core //非法指针,导致coredump
massif
堆栈分析器,指示程序中使用了多少堆内存等信息。它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。
Massif对内存的分配和释放做profile。程序开发者通过它可以深入了解程序的内存使用行为,从而对内存使用进行优化。这个功能对C++尤其有用,因为C++有很多隐藏的内存分配和释放
Helgrind
它主要用来检查多线程程序中出现的竞争问题。Helgrind寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方,而且会导致难以发掘的错误。不过,Helgrind仍然处于实验阶段。
memcheck的常用选项
—tool=
最常用的选项。运行valgrind中名为toolname的工具。如果省略工具名,默认运行memcheck。
—leak-check=
用于控制内存泄漏检测力度。
no,不检测内存泄漏;
summary,仅报告总共泄漏的数量,不报告具体泄漏位置;
yes/full,报告泄漏总数、泄漏的具体位置
—show-reachable=
用于控制是否检测控制范围之外的泄漏,比如全局指针、static指针等。
—undef-value-errors=
用于控制是否检测代码中使用未初始化变量的情况。
—log-file=filename # 将结果输出到文件,支持相对路径
—track-fds=
五种泄露内存的类型
- definitely lost:确认丢失。程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。
indirectly lost:间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与”definitely lost”一起出现,只要修复”definitely lost”即可。例子可参考我的例程。
possibly lost:可能丢失。大多数情况下应视为与”definitely lost”一样需要尽快修复,除非你的程序让一个指针指向一块动态分配的内存(但不是这块内存起始地址),然后通过运算得到这块内存起始地址,再释放它。例子可参考我的例程。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存的起始地址,但可以访问其中的某一部分数据,则会报这个错误。
still reachable:可以访问,未丢失但也未释放。如果程序是正常结束的,那么它可能不会造成程序崩溃,但长时间运行有可能耗尽系统资源,因此笔者建议修复它。如果程序是崩溃(如访问非法的地址而崩溃)而非正常结束的,则应当暂时忽略它,先修复导致程序崩溃的错误,然后重新检测。
suppressed:已被解决。出现了内存泄露但系统自动处理了。可以无视这类错误。这类错误我没能用例程触发,看官方的解释也不太清楚是操作系统处理的还是valgrind,也没有遇到过。