分类: C/C++
问题提出:
如果一个较复杂的程序,有内存泄漏,如何检测?
在windows下,VC本身带有内存泄漏的检查,程序结束时输出窗口会提示有多少memory leaks. linux下有什么办法呢?
1.发现内存泄漏,可以用top或ps。
zhouhh@zhh64:~/smscore$ top | grep firefox
会持续打印firefox的内存占用状况,可以重定向到文件中。
2.静态检测
用splint, PC-LINT,IBM的 BEAM(IBM Checking Tool for Bugs Errors and Mistakes)等。在本文略过。
3.动态检测
有IBM的rational purify,开源的valgrind. 本文主要介绍valgrind。
Valgrind 现在提供多个工具,其中最重要的是 Memcheck,Cachegrind,Massif 和 Callgrind。Valgrind 是在 Linux 系统下开发应用程序时用于调试内存问题的工具。它尤其擅长发现内存管理的问题,它可以检查程序运行时的内存泄漏问题。其中的 memecheck 工具可以用来寻找 c、c++ 程序中内存管理的错误。可以检查出下列几种内存操作上的错误:
* 读写已经释放的内存
* 读写内存块越界(从前或者从后)
* 使用还未初始化的变量
* 将无意义的参数传递给系统调用
* 内存泄漏
valgrind网址:http://valgrind.org/。到现在为止最新版:3.60,支持ubuntu 10.10.对centos 5.2可以直接编译安装使用,ubuntu中遇到一些问题。
3.1下载
zhouhh@zhh64:~/valgrind$ wget http://valgrind.org/downloads/valgrind-3.6.0.tar.bz2
我开始用较老的版本,configure时遇到glibc版本太新的问题。
zhouhh@zhh64:~/valgrind/valgrind-3.4.1$ ./configure
…
checking the GLIBC_VERSION version… unsupported version
configure: error: Valgrind requires glibc version 2.2 – 2.10
我的系统环境:
zhouhh@zhh64:~$ uname -a
Linux zhh64 2.6.35-24-generic #42-Ubuntu SMP Thu Dec 2 02:41:37 UTC 2010 x86_64 GNU/Linux
zhouhh@zhh64:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.10
DISTRIB_CODENAME=maverick
DISTRIB_DESCRIPTION=”Ubuntu 10.10″
zhouhh@zhh64:~$ ls -l /lib/libc.so.6
lrwxrwxrwx 1 root root 14 2010-11-22 09:58 /lib/libc.so.6 -> libc-2.12.1.sozhouhh@zhh64:~$ ls /lib/libc*
/lib/libc-2.12.1.so
zhouhh@zhh64:~$ /lib/libc.so.6
GNU C Library (Ubuntu EGLIBC 2.12.1-0ubuntu10) stable release version 2.12.1, by Roland McGrath et al.zhouhh@zhh64:~$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
下载完成后,解压tar xvf valgrind-3.6.0.tar.bz2,然后configure,编译安装,都没有问题。
zhouhh@zhh64:~/valgrind/valgrind-3.6.0$ ./configure
zhouhh@zhh64:~/valgrind/valgrind-3.6.0$ make
zhouhh@zhh64:~/valgrind/valgrind-3.6.0$ sudo make install
3.2执行检测
zhouhh@zhh64:~/test$ valgrind –leak-check=yes ./bin/myprog
valgrind: Fatal error at startup: a function redirection
valgrind: which is mandatory for this platform-tool combination
valgrind: cannot be set up. Details of the redirection are:
valgrind:
valgrind: A must-be-redirected function
valgrind: whose name matches the pattern: strlen
valgrind: in an object with soname matching: ld-linux-x86-64.so.2
valgrind: was not found whilst processing
valgrind: symbols from the object with soname: ld-linux-x86-64.so.2
valgrind:
valgrind: Possible fixes: (1, short term): install glibc’s debuginfo
valgrind: package on this machine. (2, longer term): ask the packagers
valgrind: for your Linux distribution to please in future ship a non-
valgrind: stripped ld.so (or whatever the dynamic linker .so is called)
valgrind: that exports the above-named function using the standard
valgrind: calling conventions for this platform.
valgrind:
valgrind: Cannot continue — exiting now. Sorry.
发现程序中使用了strlen,valgrind就直接退出了。原因是glibc没有debuginfo.
安装glibc的debug info:
zhouhh@zhh64:~$ sudo apt-cache search libc6-dbg
libc6-dbg – Embedded GNU C Library: detached debugging symbols
libc6-dbg-armel-cross – Embedded GNU C Library: detached debugging symbols (for cross-compiling)
zhouhh@zhh64:~$ sudo apt-get install libc6-dbg
再执行,程序结束时,就会有内存泄漏的提示了。
4.测试
vi testmem.c
编译:
zhouhh@zhh64:~/test$ gcc -g -O0 -o testmem testmem.c
执行:
zhouhh@zhh64:~/test$ valgrind –leak-check=yes testmem
valgrind: testmem: command not found
zhouhh@zhh64:~/test$ valgrind –leak-check=yes ./testmem
==14783== Memcheck, a memory error detector
==14783== Copyright (C) 2002-2010, and GNU GPL’d, by Julian Seward et al.
==14783== Using Valgrind-3.6.0 and LibVEX; rerun with -h for copyright info
==14783== Command: ./testmem
==14783==
==14783== Invalid write of size 4
==14783== at 0×400512: f (testmem.c:6)
==14783== by 0×400522: main (testmem.c:11)
==14783== Address 0x51b1068 is 0 bytes after a block of size 40 alloc’d
==14783== at 0x4C2827C: malloc (vg_replace_malloc.c:236)
==14783== by 0×400505: f (testmem.c:5)
==14783== by 0×400522: main (testmem.c:11)
==14783==
==14783==
==14783== HEAP SUMMARY:
==14783== in use at exit: 40 bytes in 1 blocks
==14783== total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==14783==
==14783== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==14783== at 0x4C2827C: malloc (vg_replace_malloc.c:236)
==14783== by 0×400505: f (testmem.c:5)
==14783== by 0×400522: main (testmem.c:11)
==14783==
==14783== LEAK SUMMARY:
==14783== definitely lost: 40 bytes in 1 blocks
==14783== indirectly lost: 0 bytes in 0 blocks
==14783== possibly lost: 0 bytes in 0 blocks
==14783== still reachable: 0 bytes in 0 blocks
==14783== suppressed: 0 bytes in 0 blocks
==14783==
==14783== For counts of detected and suppressed errors, rerun with: -v
==14783== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)
可以看到,40 bytes in 1 blocks are definitely lost in loss record 1 of 1
by 0×400505: f (testmem.c:5)
所以testmem.c第5行有40byte的泄漏。
查看源码,int* x = malloc(10 * sizeof(int));分配的内存没有释放。
其中,–leak-check=yes表示检测内存。
如果程序原来执行命令是
myprog var1 var2
则用valgrind检测的执行命令是
valgrind –leak-check=yes myprog var1 var2
程序gcc的编译选项必须带-g, 最好带-O0,表示没有优化,方便定位问题。
5.参考
http://valgrind.org/docs/manual/quick-start.html
http://www.ibm.com/developerworks/cn/linux/l-cn-memleak/index.html
http://fafeng.blogbus.com/logs/7525571.html