valgrind 介绍
valgrind 是一个 GPL 软件,用于 Linux ( For x86 ,amd64 and mips ...) 程序的内存调试和代码分析。使用 valgrind 的工具包,可以自动检测许多内存管理和线程的bug,让你的程序运行的更加稳定。
valgrind 的工具包包含多个工具:
- memcheck:内存检查
- 使用未初始化的内存:Use of uninitialised memory
- 使用已释放的内存 :Reading/writing memory after it has been free’d
- 使用超过malloc分配的内存空间:Reading/writing off the end of malloc’d blocks
- 对堆栈的非法访问:Reading/writing inappropriate areas on the stack
- 申请的空间是否有释放:Memory leaks – where pointers to malloc’d blocks are lost forever
- malloc/free/new/delete 申请和释放内存的匹配:Mismatched use of malloc/new/new [] vs free/delete/delete []
- src和dst的重叠:Overlapping src and dst pointers in memcpy() and related functions
- callgrind:收集程序运行的一些数据,函数调用关系等。还可以有选择的进行cache模拟。在运行结束,他会把分析数据写入一个文件,callgrind_annotate 可以把这个文件内容转换成可读形式。
- cachegrind:它模拟 CPU中的一级缓存I1,D1和L2二级缓存,能够精确地指出程序中 cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数。这对优化程序有很大的帮助。
- helgrind:它主要用来检查多线程程序中出现的竞争问题。Helgrind寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方,而且会导致难以发掘的错误。
- massif:堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。
valgrind 安装和编译
下载
wget http://valgrind.org/downloads/valgrind-3.12.0.tar.bz2
编译及安装
以 mips,uclibc环境为例
--host:指定交叉编译工具链,默认glibc
--prefix:指定安装路径
-muclibc:指定uclibc环境
-D__UCLIBC__:define __UCLIBC__。valgrind 需要定义这个宏否则运行报错。
./autogen.sh ./configure --host=mips-linux-gnu CFLAGS="-D__UCLIBC__ -muclibc" --prefix=/home_a/wxyang/nfsroot/t30/valgrind/ make make install
安装工具集
valgrind 应用实例分析
启动开发板,设置环境变量:
export VALGRIND_LIB=/mnt/t30/valgrind/lib/valgrind export PATH=/mnt/t30/valgrind/bin/:$PATH
启动应用程序:
valgrind --log-file=valgrind.log --tool=memcheck --leak-check=full --show-reachable=yes ./test
--tool=memcheck:设置启动工具为memcheck --leak-check=full:完全检查内存泄漏
--log-file=valgrind.log:输出日志文件 --show-reachable=yes:检测控制范围之外的泄漏
注意:应用程序编译时加上-g, 尽量不要用O2优化(用-O0),同时不要用 strip 压缩,否则看不到详细信息。
日志分析:常见错误
- malloc/free: in use at exit :内存在退出前没有释放
- invalid write of size :非法写入内存,一般为数组越界
- invalid read of size :非法读内存:一般为数组越界
- definitely lost /possibly lost /still reachable in loss record:内存未释放
- definitely :确认丢失。程序中存在内存泄露,应尽快修复。
- indirectly:间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误 。
- possibly:可能丢失。大多数情况下应视为与"definitely lost"一样需要尽快修复。
- still reachable:可以访问,未丢失但也未释放。如果程序是正常结束的,那么它可能不会造成程序崩溃,但长时间运行有可能耗尽系统资源。
- suppressed:已被解决。出现了内存泄露但系统自动处理了。可以无视这类错误。
- invalid free()/delete/delete[] :同一指针被多次释放
- source and destination overlay :一般是使用strncpy,memcpy引起
- syscall param contains uninitialized byte:调用系统函数时传入了未初始化的变量
- conditional jump or move depends on uninitialized value :条件判断时使用了未初始化的变量
- access not with mapped region/stack overflow :栈溢出
- mismatch free()/delete/delete[]/new :delete/malloc/free搭配错误
错误举例
indirectly lost:如图可以追溯到具体文件及函数调用,明显是cjson使用有问题。
still reachable:
总结
- 本文简单介绍 valgrind 安装和使用,以及对内存泄漏简单分析,算是提供一种排查思路;
- 通常自己写的程序一般有些许掌控力,不过对于大型项目,多人协助,以及引入的第三方库,难免会遗留一些bug。这个时候就需要一些工具辅助排查了,能够大大提升效率。
- 希望本文对你,有些许帮助。