Valgrind 工具介绍

Valgrind 工具介绍.
官网:http://www.valgrind.org/。 
Introduction of Valgrind
1. Introduction 
Valgrind是一个GPL的软件,用于Linux(For x86, amd64 and ppc32)程序的内存调试和代码剖析。你可以在它的环境中运行你的程序来监视内存的使用情况, 
比如C 语言中的malloc和free或者 C++中的new和 delete。使用Valgrind的工具包,你可以自动的检测许多内存管理和线程的bug,避免花费太多的时间在bug寻找上, 
使得你的程序更加稳固。Valgrind工具包包含多个工具,如Memcheck,Cachegrind,Helgrind, Callgrind,Massif。 

2. Valgrind的作用。 
2.1 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) 

2.2 Callgrind 
Callgrind收集程序运行时的一些数据,函数调用关系等信息,还可以有选择地进行cache 模拟。 
在运行结束时,它会把分析数据写入一个文件。callgrind_annotate可以把这个文件的内容转化成可读的形式。 

2.3 Cachegrind 
它模拟 CPU中的一级缓存I1,D1和L2二级缓存,能够精确地指出程序中 cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数, 
内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数。这对优化程序有很大的帮助。 

2.4 Helgrind 
它主要用来检查多线程程序中出现的竞争问题。Helgrind 寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方, 
而且会导致难以发掘的错误。Helgrind实现了名为” Eraser” 的竞争检测算法,并做了进一步改进,减少了报告错误的次数。 

2.5 Massif 
堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中, 
它还能够加速我们程序的运行,减少程序停留在交换区中的几率。 
Valgrind是免费的,可以到官网去下载,阅读源代码,并且进行修改。 

Set up environment for Valgrind 
与code viser debug一样,Valgrind也需要软件是debug版的,而且要求更严格,板子上的/lib/下的library都需要是debug版(-g),而且最好不要使用优化选项(-O0)。 
原因是Valgrind抓取callstack是从下往上,如果下层的library不是debug版的,那么上面app的callstack就不会打出来。当前Valgrind本身也是debug版的。 
针对我们的平台,需要替换的library主要有两个地方:/lib/和/basic/。在sys_build的加上BUILD_CFG=debug,但是当把pkg烧入板子后,这些library的debug symbol有可能被拿掉, 
所以我们需要手动去替换debug版的library。 
/lib/下面的library默认是release版(不管sys_build是否有加debug),不过在/mtkoss/gnuarm/vfp_4.5.1_2.6.27_cortex-a9-rhe14/i686/sysroot/lib/有debug版的library, 
怎么把这些library替换板子/lib/下的so?下面有一种办法可以做到,不过需要板子有足够的Dram: 
A. 用mtkbuild将/mtkoss/…/lib/下面的library拷贝出来,放入U盘lib目录。 
B. tar -czvf /mnt/usb/sda1/lib.tar.gz /lib/,将板子的/lib/压缩到U盘。 
C. tar -zxvf /mnt/usb/sda1/lib.tar.gz /tmp/,将/lib/解压到/tmp/目录。 
D. cp /mnt/usb/sda1/lib/* /tmp/lib/ -f,将U盘中的debug library替换进来。 
E. mount -o bind /tmp/lib/ /lib/,将/lib/绑定到/tmp/lib/,这样程序运行时链接library时会找到/tmp/lib/目录下的.so。 
F. 同样的方法将/basic中的library替换成debug版的。 
注:/mtkoss/…/lib/这个路径是在build server(mszsdtlt02或其他)上就可以看到。 
当确定把系统中的主要library都替换成debug版后,设置环境变量LD_LIBRARY_PATH和PATH--加入Valgrind的bin和lib路径。 
因为Valgrind中的路径是写死的(/3rd/Valgrind),所以我们必须把Valgrind拷贝到/3rd/。 

Run you app with Valgrind 
一切准备就绪,现在就开始测试吧。 
执行命令是:valgrind --leak-resolution=med --leak-check=full <command>。前面部分一般都不用更改,至于这些选项可以通过valgrind --help来查看。 
--leak-check=full 指的是完全检查内存泄漏。command即你要执行的app命令。例如:./bestvui -qws。回车即可。 
程序Run的过程中你会看到很多log,那是Valgrind在分析你的代码。因此程序执行效率会降低,比平常要慢上10-20倍。 
在程序退出时,Valgrind会统计出整个程序执行过程中的memory leak情况。如果你的library都是debug版的话,你可以看到非常详细的callstack,然后根据这些信息去修改你的代码吧。 
注:如果程序没办法退出,用Ctrl+C和Kill也是可以的,并不会影响Valgrind工作。
 
How to check the information 
在程序执行过程中和退出程序时Valgrind都会打印很多信息,下面简单介绍几种常见的信息: 
/********使用未初始化的值*******/
==5520== Use of uninitialised value of size 4
==5520==    at 0x4DB7960: Curl_httpchunk_read (in /3rd/yahoo_widget/libKonfabulator.so.0.0.0)
/********条件判断depend on未初始化的值*******/
==5520== Conditional jump or move depends on uninitialised value(s)
==5520==    at 0x4DB779C: Curl_httpchunk_read (in /3rd/yahoo_widget/libKonfabulator.so.0.0.0)

未初始化的值一般情况下有两种情形容易出现这个错误:程序中的局部变量未初始化;C语言malloc的内存未初始化;C++中new的对象其成员未被初始化。 
/********数组越界错误*******/
==5520== Invalid write of size 4      
==5520==    at 0x8048384: f (test.c:6)
==5520==    by 0x80483AC: main (test.c:11)
==5520==  Address 0x400C050 is 0 bytes after a block of size 40 alloc'd
==5520==    at 0x40046F2: malloc (vg_replace_malloc.c:149)
==5520==    by 0x8048377: f (test.c:5)
==5520==    by 0x80483AC: main (test.c:11)

这个错误的发生是因为对一些memcheck猜想不应该访问的内存进行了读写。 
/********内存空间未释放******/
==5520== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5520==    at 0x40046F2: malloc (vg_replace_malloc.c:149)
==5520==    by 0x8048377: f (test.c:5)
==5520==    by 0x80483AC: main (test.c:11)

在程序退出时打印的信息: 
==12336== HEAP SUMMARY:
==12336==     in use at exit: 307,352 bytes in 3,736 blocks
==12336==   total heap usage: 8,814 allocs, 5,079 frees, 250,065,302 bytes alloc
统计出使用的alloc和free次数,以及alloc多少字节。

==12336== LEAK SUMMARY:
==12336==    definitely lost: 1,320 bytes in 16 blocks
==12336==    indirectly lost: 47,840 bytes in 598 blocks
==12336==      possibly lost: 1,008 bytes in 7 blocks
==12336==    still reachable: 257,184 bytes in 3,115 blocks
==12336==         suppressed: 0 bytes in 0 blocks

still reachable: 表示泄漏的内存在程序运行完的时候,仍旧有指针指向它,因而,这种内存在程序运行结束之前可以释放。一般情况下valgrind不会报这种泄漏, 
除非使用了参数 --show- reachable=yes。 

definitely lost: 明确地已经泄漏了,因为在程序运行完的时候,没有指针指向它, 指向它的指针在程序中丢失了。一般这种泄漏常见,而且比较难发现问题所在。 

possibly lost: 发现了一个指向某块内存中部的指针,而不是指向内存块头部。这种指针一般是原先指向内存块头部,后来移动到了内存块的中部,还有可能该指针和该内存根本就没有关系, 
检测工具只是怀疑有内存泄漏。 

下面说明什么是indirectly lost 
(1)RRR ---------------------------------------> BBB 
(2)RRR -------------->AAA ------------------> BBB 
(3)RRR BBB 
(4)RRR AAA ------------------> BBB 
BBB在case(1),(2)情况下是still reachable。case(3)是Definitely lost,case(4)是Indirectly lost。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值