zoukankan      html  css  js  c++  java
  • 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;

    }

    运行如下:

    huerjia@huerjia:~/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;

    }

    运行如下:

    huerjia@huerjia:~/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就是能够帮助你实现这一目标的 出色工具。

  • 相关阅读:
    【Codeforces 349B】Color the Fence
    【Codeforces 459D】Pashmak and Parmida's problem
    【Codeforces 467C】George and Job
    【Codeforces 161D】Distance in Tree
    【Codeforces 522A】Reposts
    【Codeforces 225C】Barcode
    【Codeforces 446A】DZY Loves Sequences
    【Codeforces 429B】Working out
    【Codeforces 478C】Table Decorations
    【Codeforces 478C】Table Decorations
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/4061075.html
Copyright © 2011-2022 走看看