用valgrind检查C++程序的内存泄漏

作者:, 发表于

C++内存检查和性能分析工具valgrind里介绍了valgrind的安装,以及用于效率分析profiler工具。valgrind最本来的功能是内存检查。这篇文章做简单的介绍。

1.内存检查的基本命令

基本命令是:

valgrind [valgrind-paras] your-program [you-program-paras]

常见选项有:

选项 解释
--leak-check=full 检查所有错误信息
--show-leak-kinds=all 显示所有错误详情

valgrind会输出很多结果。从大类可以分为内存泄漏检查结果和其它内存错误结果。

2.valgrind检查的内存泄漏结果

2.1.内存泄漏的四个类型 LEAK SUMMARY

内存泄漏被分为四种:

错误类型 解释
definitely lost 内存泄漏,并且没有变量指向该内存。
indirectly lost 内存泄漏,所有指向该内存的变量已泄漏。indirectly lost一般预示有definitely lost错误,解决后者就解决了前者。
possible lost 内存未被删除,有变量指向内存中间位置。
still reachable 内存未被删除,有全局变量指向内存起始处。

still reachable跟全局变量有关,它的泄漏是一次性行为。因此大家认为still reachable的影响不严重,valgrind也默认不显示详情。若想查看still reachable的错误详情,需增加--show-leak-kinds=all选项。前两类错误则可能在程序运行过程中不断泄漏内存从而引起系统奔溃,尤其是需长时间运行的服务器程序。

valgrind会给出四类错误的统计数据:

==86262== LEAK SUMMARY:
==86262==    definitely lost: 96 bytes in 12 blocks
==86262==    indirectly lost: 0 bytes in 0 blocks
==86262==      possibly lost: 0 bytes in 0 blocks
==86262==    still reachable: 24,076 bytes in 54 blocks
==86262==         suppressed: 0 bytes in 0 blocks 

其中86262是进程id。

2.2.错误代码示例

#include <memory.h>

struct Link {
    Link* next;
};


Link* still_reachable;
Link* possible_lost;

int main()
{
    Link* definitely_lost = new Link;

    Link* whose_next_is_indirectly_lost = new Link;
    whose_next_is_indirectly_lost->next = new Link;

    still_reachable = new Link;

    possible_lost = new Link[2] + 1;
}

它存在上面四类内存错误:

==144815== LEAK SUMMARY:
==144815==    definitely lost: 16 bytes in 2 blocks
==144815==    indirectly lost: 8 bytes in 1 blocks
==144815==      possibly lost: 16 bytes in 1 blocks
==144815==    still reachable: 8 bytes in 1 blocks

2.3.错误详情示例

上面示例代码的错误详情如下。每个错误都会标记错误路径,用户可以很方便地查找到具体是哪一行代码引起的内存泄漏。

==144815== 8 bytes in 1 blocks are still reachable in loss record 1 of 5
==144815==    at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==144815==    by 0x40068B: main (valgrind.cpp:18)
==144815== 
==144815== 8 bytes in 1 blocks are indirectly lost in loss record 2 of 5
==144815==    at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==144815==    by 0x40067A: main (valgrind.cpp:16)
==144815== 
==144815== 8 bytes in 1 blocks are definitely lost in loss record 3 of 5
==144815==    at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==144815==    by 0x40065E: main (valgrind.cpp:13)
==144815== 
==144815== 16 bytes in 1 blocks are possibly lost in loss record 4 of 5
==144815==    at 0x4C2B800: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==144815==    by 0x40069C: main (valgrind.cpp:20)
==144815== 
==144815== 16 (8 direct, 8 indirect) bytes in 1 blocks are definitely lost in loss record 5 of 5
==144815==    at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==144815==    by 0x40066C: main (valgrind.cpp:15)

16 bytes是指泄漏的区域大小。1 blocks是指有多少个区域。同一运行路径泄漏的代码会合并到一条记录。因此有时候会出现400 bytes in 10 blocks are definitely lost的错误信息。

3.valgrind提供的其它内存异常结果

3.1.内存越界 invalid write of size ddd

错误信息示例如下。一般是指数组访问位置越界等。

  ==19182== Invalid write of size 4
  ==19182==    at 0x804838F: f (example.c:6)
  ==19182==    by 0x80483AB: main (example.c:11)
  ==19182==  Address 0x1BA45050 is 0 bytes after a block of size 40 alloc'd
  ==19182==    at 0x1B8FF5CD: malloc (vg_replace_malloc.c:130)
  ==19182==    by 0x8048385: f (example.c:5)
  ==19182==    by 0x80483AB: main (example.c:11)

size是指越界的区域大小。

3.2.未初始化 uses of uninitialised values

未初始化信息是一颗雷,有时候不会影响程序结果,但有时候会出错。示例的错误信息如下:

Conditional jump or move depends on uninitialised value(s)
   at 0x402DFA94: _IO_vfprintf (_itoa.h:49)
   by 0x402E8476: _IO_printf (printf.c:36)
   by 0x8048472: main (tests/manuel1.c:8)

3.3.重复释放内存 invalid free

freedelete重复删除内存,会导致程序出错。

Invalid free()
   at 0x4004FFDF: free (vg_clientmalloc.c:577)
   by 0x80484C7: main (tests/doublefree.c:10)
 Address 0x3807F7B4 is 0 bytes inside a block of size 177 free'd
   at 0x4004FFDF: free (vg_clientmalloc.c:577)
   by 0x80484C7: main (tests/doublefree.c:10)

Q.E.D.


上一篇:C++内存检查和性能分析工具valgrind2016年1月5日
一个好用的C++性能分析工具需满足几个条件: 配置简单,不需要改动原程序和重新编译。 可以跟踪到动态链接库内部。 有结果的图形界面,

下一篇:C++的浮点数取整2016年3月5日
C++的浮点数转整数有四种方法,直接类型转换、round、floor、ceil。其效果如下表: x -1.9 -1.5 -1.1 1.1 1.5 1.9 static_cast<int>(x) -1 -1 -1 1


  • 支持使用微薄、微信和QQ的账户登陆进行评论。由各自网站直接认证,不会泄露你的密码。
  • 登陆后可选择分享评论到所绑定的社交网络,如微薄、人人和QQ空间。
  • 评论提交后无法修改。如需修改,请删除原评论再重新提交。
  • 评论支持LaTeX代码,行内公式请用\(a+b=c\),行间公式请用\[a+b=c\]。公式只支持英文字符。