感谢支持
我们一直在努力

Linux下Valgrind的使用概述

Valgrind简介:


Valgrind是动态分析工具的框架。有很多Valgrind工具可以自动的检测许多内存管理和多进程/线程的bugs,在细节上剖析你的程序。你也可以利用Valgrind框架来实现自己的工具。


Valgrind通常包括6个工具:一个内存错误侦测工具,两个线程错误侦测工具,cache和分支预测的分析工具,堆的分析工具。


Valgrind的使用与CPU OS以及编译器和C库都有关系。目前支持下面的平台:


– x86/Linux


– AMD64/Linux


– PPC32/Linux


– PPC64/Linux


– ARM/Linux


– x86/MacOSX


– AMD64/MacOSX


Valgrind是GNU v2下的开源软件,你可以从http://valgrind.org下载最新的源代码。


Valgrind的安装:


1.从http://valgrind.org下载最新的valgrind-3.7.0.tar.bz2d,用tar -xfvalgrind-3.7.0.tar.bz2解压安装包。


2.执行./configure,检查安装要求的配置。


3.执行make。


4.执行make install,最好是用root权限。


5.试着valgrind ls -l来检测是否正常工作。


Valgrind的概述:


Valgrind时建立动态分析工具的框架。它有一系列用于调试分析的工具。Valgrind的架构是组件化的,所以可以方便的添加新的工具而不影响当前的结构。


下面的工具是安装时的标准配置:


Memcheck:用于检测内存错误。它帮助c和c++的程序更正确。


Cachegrind:用于分析cache和分支预测。它帮助程序执行得更快。


Callgrind:用于函数调用的分析。


Helgrind:用于分析多线程。


DRD:也用于分析多线程。与Helgrind类似,但是用不同的分析技术,所以可以检测不同的问题。


Massif:用于分析堆。它帮助程序精简内存的使用。


SGcheck:检测栈和全局数组溢出的实验性工具,它和Memcheck互补使用。

Valgrind的使用:


1.准备好程序:


编译程序时用-g,这样编译后的文件包含调试信息,那Memcheck的分析信息中就包含正确的行号。最好使用-O0的优化等级,使用-O2及以上的优化等级使用时可能会有问题。


2.在Memcheck下运行程序:


如果你的程序执行如下:


myprog arg1 arg2


那么使用如下:


valgrind –leak-check=yes myprog arg1 arg2


Memcheck是默认的工具。–leak-check打开内存泄漏检测的细节。


在上面的命令中运行程序会使得程序运行很慢,而且占用大量的内存。Memcheck会显示内存错误和检测到的内存泄漏。


3.如何查看Memcheck的输出:


这里有一个实例c代码(a.c),有一个内存错误和一个内存泄漏。


#include <stdlib.h>


void f(void)


{


         int*x = (int *)malloc(10 * sizeof(int));


         x[10]= 0;


         //problem 1: heap block overrun


}        //problem 2: memory leak — x not freed


 


int main(void)


{


         f();


         return0;


}


 


运行如下:


www.linuxidc.com @linuxidc:~/NFS/valg/test$ valgrind–leak-check=yes ./a


==24780== Memcheck, a memory error detector


==24780== Copyright (C) 2002-2011, and GNUGPL’d, by Julian Seward et al.


==24780== Using Valgrind-3.7.0 and LibVEX;rerun with -h for copyright info


==24780== Command: ./a


==24780==


==24780== Invalid write of size 4


==24780==   at 0x80484DF: f() (a.c:5)


==24780==   by 0x80484F1: main (a.c:11)


==24780== Address 0x42d3050 is 0 bytes after a block of size 40 alloc’d


==24780==   at 0x4026444: malloc (vg_replace_malloc.c:263)


==24780==   by 0x80484D5: f() (a.c:4)


==24780==   by 0x80484F1: main (a.c:11)


==24780==


==24780==


==24780== HEAP SUMMARY:


==24780==     in use at exit: 40 bytes in 1 blocks


==24780==  total heap usage: 1 allocs, 0 frees, 40 bytes allocated


==24780==


==24780== 40 bytes in 1 blocks aredefinitely lost in loss record 1 of 1


==24780==   at 0x4026444: malloc (vg_replace_malloc.c:263)


==24780==   by 0x80484D5: f() (a.c:4)


==24780==   by 0x80484F1: main (a.c:11)


==24780==


==24780== LEAK SUMMARY:


==24780==   definitely lost: 40 bytes in 1 blocks


==24780==   indirectly lost: 0 bytes in 0 blocks


==24780==      possibly lost: 0 bytes in 0 blocks


==24780==   still reachable: 0 bytes in 0 blocks


==24780==         suppressed: 0 bytes in 0 blocks


==24780==


==24780== For counts of detected andsuppressed errors, rerun with: -v


==24780== ERROR SUMMARY: 2 errors from 2contexts (suppressed: 17 from 6)


 


如何来阅读这个输出结果:


==24780== Memcheck, a memory error detector


==24780== Copyright (C) 2002-2011, and GNUGPL’d, by Julian Seward et al.


==24780== Using Valgrind-3.7.0 and LibVEX;rerun with -h for copyright info


==24780== Command: ./a


这一部分是显示使用的工具以及版本信息。其中24780是Process ID。


 


==24780== Invalid write of size 4


==24780==   at 0x80484DF: f() (a.c:5)


==24780==   by 0x80484F1: main (a.c:11)


==24780== Address 0x42d3050 is 0 bytes after a block of size 40 alloc’d


==24780==   at 0x4026444: malloc (vg_replace_malloc.c:263)


==24780==   by 0x80484D5: f() (a.c:4)


==24780==   by 0x80484F1: main (a.c:11)


这部分指出了错误:Invalid write。后面的几行显示了函数堆栈。


 


==24780== HEAP SUMMARY:


==24780==     in use at exit: 40 bytes in 1 blocks


==24780==  total heap usage: 1 allocs, 0 frees, 40 bytes allocated


==24780==


==24780== 40 bytes in 1 blocks aredefinitely lost in loss record 1 of 1


==24780==   at 0x4026444: malloc (vg_replace_malloc.c:263)


==24780==   by 0x80484D5: f() (a.c:4)


==24780==   by 0x80484F1: main (a.c:11)


==24780==


==24780== LEAK SUMMARY:


==24780==   definitely lost: 40 bytes in 1 blocks


==24780==   indirectly lost: 0 bytes in 0 blocks


==24780==      possibly lost: 0 bytes in 0 blocks


==24780==   still reachable: 0 bytes in 0 blocks


==24780==         suppressed: 0 bytes in 0 blocks


这部分是对堆和泄漏的总结,可以看出内存泄漏的错误。


==24780== For counts of detected andsuppressed errors, rerun with: -v


==24780== ERROR SUMMARY: 2 errors from 2contexts (suppressed: 17 from 6)


这部分是堆所有检测到的错误的总结。代码中的两个错误都检测到了。

Helgrind:线程错误检测工具


若使用这个工具,在Valgrind的命令中添加–tool=helgrind。


Helgrind用于c,c++下使用POSIXpthreads的程序的线程同步错误。


Helgrind可以检测下面三类错误:


1.POSIX pthreads API的错误使用


2.由加锁和解锁顺序引起的潜在的死锁


3.数据竞态–在没有锁或者同步机制下访问内存


以数据竞态为例来说明Helgrind的用法:


在不使用合适的锁或者其他同步机制来保证单线程访问时,两个或者多个线程访问同一块内存就可能引发数据竞态。


一个简单的数据竞态的例子:


#include <pthread.h>


int var = 0;


 


void* child_fn ( void* arg ) {


         var++;/* Unprotected relative to parent */ /* this is line 6 */


         returnNULL;


}


 


int main ( void ) {


         pthread_tchild;


         pthread_create(&child,NULL, child_fn, NULL);


         var++;/* Unprotected relative to child */ /* this is line 13 */


         pthread_join(child,NULL);


         return0;


}


 


运行如下:


www.linuxidc.com @linuxidc:~/NFS/valg/test$ valgrind–tool=helgrind ./b


==25449== Helgrind, a thread error detector


==25449== Copyright (C) 2007-2011, and GNUGPL’d, by OpenWorks LLP et al.


==25449== Using Valgrind-3.7.0 and LibVEX;rerun with -h for copyright info


==25449== Command: ./b


==25449==


==25449==—Thread-Announcement——————————————


==25449==


==25449== Thread #1 is the program’s rootthread


==25449==


==25449== —Thread-Announcement——————————————


==25449==


==25449== Thread #2 was created


==25449==   at 0x4123A38: clone (in /lib/tls/i686/cmov/libc-2.11.1.so)


==25449==   by 0x40430EA: pthread_create@@GLIBC_2.1 (in /lib/tls/i686/cmov/libpthread-2.11.1.so)


==25449==   by 0x402A9AD: pthread_create_WRK (hg_intercepts.c:255)


==25449==   by 0x402AA85: pthread_create@* (hg_intercepts.c:286)


==25449==   by 0x80484E1: main (b.c:11)


==25449==


==25449==—————————————————————-


==25449==


==25449== Possible data race during read ofsize 4 at 0x804A020 by thread #1


==25449== Locks held: none


==25449==   at 0x80484E2: main (b.c:12)


==25449==


==25449== This conflicts with a previouswrite of size 4 by thread #2


==25449== Locks held: none


==25449==   at 0x80484A7: child_fn (b.c:6)


==25449==   by 0x402AB04: mythread_wrapper (hg_intercepts.c:219)


==25449==   by 0x404296D: start_thread (in /lib/tls/i686/cmov/libpthread-2.11.1.so)


==25449==   by 0x4123A4D: clone (in /lib/tls/i686/cmov/libc-2.11.1.so)


==25449==


==25449==—————————————————————-


==25449==


==25449== Possible data race during writeof size 4 at 0x804A020 by thread #1


==25449== Locks held: none


==25449==   at 0x80484E2: main (b.c:12)


==25449==


==25449== This conflicts with a previouswrite of size 4 by thread #2


==25449== Locks held: none


==25449==   at 0x80484A7: child_fn (b.c:6)


==25449==   by 0x402AB04: mythread_wrapper (hg_intercepts.c:219)


==25449==   by 0x404296D: start_thread (in /lib/tls/i686/cmov/libpthread-2.11.1.so)


==25449==   by 0x4123A4D: clone (in /lib/tls/i686/cmov/libc-2.11.1.so)


==25449==


==25449==


==25449== For counts of detected andsuppressed errors, rerun with: -v


==25449== Use –history-level=approx or=none to gain increased speed, at


==25449== the cost of reduced accuracy ofconflicting-access information


==25449== ERROR SUMMARY: 2 errors from 2contexts (suppressed: 0 from 0)


 


错误信息从“Possible data race during write of size 4 at 0x804A020 by thread #1


”开始,这条信息你可以看到竞态访问的地址和大小,还有调用的堆栈信息。


第二条调用堆栈从“This conflicts with a previous write of size 4 by thread #2


”开始,这表明这里与第一个调用堆栈有竞态。


一旦你找到两个调用堆栈,如何找到竞态的根源:


首先通过每个调用堆栈检查代码,它们都会显示对同一个位置或者变量的访问。


现在考虑如何改正来使得多线程访问安全:


1.使用锁或者其他的同步机制,保证同一时间只有独立的访问。


2.使用条件变量等方法,确定多次访问的次序。


本文介绍了valgrind的体系结构,并重点介绍了其应用最广泛的工具:memcheck和helgrind。阐述了memcheck和helgrind的基本使用方法。在项目中尽早的发现内存问题和多进程同步问题,能够极大地提高开发效率,valgrind就是能够帮助你实现这一目标的出色工具。

赞(0) 打赏
转载请注明出处:服务器评测 » Linux下Valgrind的使用概述
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏