valgrind内存泄露检测工具

valgrind简介与使用

  • 一、valgrind简介
    • 二、安装valgrind
    • 三、valgrind使用
    • Valgrind一般包含下列工具:
    • 多线程检查工具的使用:

一、valgrind简介

Valgrind是一款用于内存调试、内存泄漏检测以及性能分析、检测线程错误的软件开发工具。

Valgrind 是运行在Linux 上的多用途代码剖析和内存调试软件。主要包括Memcheck、Callgrind、Cachegrind 等工具,每个工具都能完成一项任务调试、检测或分析。可以检测内存泄露、线程违例和Cache 的使用等。Valgrind 基于仿真方式对程序进行调试,它先于应用程序获取实际处理器的控制权,并在实际处理器的基础上仿真一个虚拟处理器,并使应用程序运行于这个虚拟处理器之上,从而对应用程序的运行进行监视。应用程序并不知道该处理器是虚拟的还是实际的,已经编译成二进制代码的应用程序并不用重新进行编译,Valgrind 直接解释二进制代码使得应用程序基于它运行,从而能够检查内存操作时可能出现的错误。所以在Valgrind下运行的程序运行速度要慢得多,而且使用的内存要多得多 - 例如,Memcheck工具下的程序是正常情况的两倍多。因此,最好在性能好的机器上使用Valgrind。

二、安装valgrind

wget https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2.

wyj@wyj-virtual-machine:~/Download$ tar -xjvf valgrind-3.15.0.tar.bz2

wyj@wyj-virtual-machine:~/Download$ cd valgrind-3.15.0/

因为valgrind支持多个平台,根据当前主机配置valgrind

wyj@wyj-virtual-machine:~/Download/valgrind-3.15.0$ ./configure

./configure之后就有makefile出现,接着就是make编译,安装

wyj@wyj-virtual-machine:~/Download/valgrind-3.15.0$ make

wyj@wyj-virtual-machine:~/Download/valgrind-3.15.0$ sudo make install

查看一下版本看看是否安装好

wyj@wyj-virtual-machine:~/Download/valgrind-3.15.0$ valgrind --version

valgrind-3.15.0

三、valgrind使用

#include 
 
#include 
 
 
void fun(void)
 
{
    int *x = malloc(10*sizeof(int));
 
    x [10] = 0; //问题1:堆块溢出
 
} //问题2:内存泄漏 -  x未释放
 
 
int main(int argc, char **argv)
 
{
 
    fun() ;
 
    return 0 ;
 
}

编译程序-g以包含调试信息,以便Memcheck的错误消在这里插入代码片息包含确切的行号。

wyj@wyj-virtual-machine:~/c_code$ gcc -g valgrind_test.c -o valgrind_test

正常运行

wyj@wyj-virtual-machine:~/c_code$ ./valgrind_test

Memcheck是默认工具。–leak-check 选项打开详细的内存泄漏检测器。程序运行速度会比正常情况慢很多(例如20到30倍),并且会占用更多内存。Memcheck将发出有关内存错误和检测到的泄漏的消息。

wyj@wyj-virtual-machine:~/c_code$ valgrind --leak-check=yes ./valgrind_test

一开始是valgrind信息“62414”表示进程号

62414 Memcheck, a memory error detector

62414 Copyright © 2002-2017, and GNU GPL’d, by Julian Seward et al.

62414 Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info

62414 Command: ./valgrind_test

程序访问非法地址的内存,无效写入

62414 Invalid write of size 4

62414 at 0x40054B: fun (valgrind_test.c:21)

62414 by 0x400566: main (valgrind_test.c:28)

62414 Address 0x5201068 is 0 bytes after a block of size 40 alloc’d

62414 at 0x4C2AEC3: malloc (vg_replace_malloc.c:309)

62414 by 0x40053E: fun (valgrind_test.c:20)

62414 by 0x400566: main (valgrind_test.c:28)

62414

堆区情况:

62414 HEAP SUMMARY:

62414 in use at exit: 40 bytes in 1 blocks

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

内存泄漏消息如下所示:

62414 40 bytes in 1 blocks are definitely lost in loss record 1 of 1

62414 at 0x4C2AEC3: malloc (vg_replace_malloc.c:309)

62414 by 0x40053E: fun (valgrind_test.c:20)

62414 by 0x400566: main (valgrind_test.c:28)

有几种泄漏; 两个最重要的类别是,肯定泄露(definitely lost),可能已经泄露(possibly lost)

62414 LEAK SUMMARY:

62414 definitely lost: 40 bytes in 1 blocks

62414 indirectly lost: 0 bytes in 0 blocks

62414 possibly lost: 0 bytes in 0 blocks

62414 still reachable: 0 bytes in 0 blocks

62414 suppressed: 0 bytes in 0 blocks

62414

62414 For lists of detected and suppressed errors, rerun with: -s

62414 ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

关于Memcheck的错误消息说明:

http://valgrind.org/docs/manual/mc-manual.html#mc-manual.errormsgs.

Valgrind直接与现有可执行文件一起使用。无需重新编译,重新链接或以其他方式修改要检查的程序。

使用方法:

wyj@wyj-virtual-machine:~/c_code$ valgrind --help

usage: valgrind [options] prog-and-args

valgrind [valgrind-options] your-prog [your-prog-options]

最重要的选项是–tool决定运行哪个Valgrind工具。例如,如果要ls -l使用内存检查工具Memcheck 运行该命令 ,请发出以下命令

wyj@wyj-virtual-machine:~$ valgrind --tool=memcheck ls -l

62521 Memcheck, a memory error detector

62521 Copyright © 2002-2017, and GNU GPL’d, by Julian Seward et al.

62521 Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info

62521 Command: ls -l

62521

总用量 148

drwxrwxr-x 9 wyj wyj 4096 12月 26 2018 apue

drwxrwxr-x 5 wyj wyj 4096 8月 11 10:40 c_code

drwxrwxr-x 2 wyj wyj 4096 7月 31 16:56 crc

drwxrwxr-x 13 wyj wyj 4096 8月 11 10:12 Download

62521

62521 HEAP SUMMARY:

62521 in use at exit: 20,073 bytes in 29 blocks

62521 total heap usage: 266 allocs, 237 frees, 94,000 bytes allocated

62521

62521 LEAK SUMMARY:

62521 definitely lost: 0 bytes in 0 blocks

62521 indirectly lost: 0 bytes in 0 blocks

62521 possibly lost: 0 bytes in 0 blocks

62521 still reachable: 20,073 bytes in 29 blocks

62521 suppressed: 0 bytes in 0 blocks

62521 Rerun with --leak-check=full to see details of leaked memory

62521

62521 For lists of detected and suppressed errors, rerun with: -s

62521 ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Memcheck是默认设置,可以不用加tool直接使用

wyj@wyj-virtual-machine:~$ valgrind ls -l

Valgrind一般包含下列工具:

1.Memcheck
最常用的工具,用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc()/free()/new/delete的调用都会被捕获。所以,它能检测以下问题:

1.对未初始化内存的使用;

2.读/写释放后的内存块;

3.读/写超出malloc分配的内存块;

4.读/写不适当的栈中内存块;

5.内存泄漏,指向一块内存的指针永远丢失;

6.不正确的malloc/free或new/delete匹配;

7,memcpy()相关函数中的dst和src指针重叠。

这些问题往往是C/C++程序员最头疼的问题,Memcheck在这里帮上了大忙。

2.Callgrind
和gprof类似的分析工具,但它对程序的运行观察更是入微,能给我们提供更多的信息。和gprof不同,它不需要在编译源代码时附加特殊选项,但加上调试选项是推荐的。Callgrind收集程序运行时的一些数据,建立函数调用关系图,还可以有选择地进行cache模拟。在运行结束时,它会把分析数据写入一个文件。callgrind_annotate可以把这个文件的内容转化成可读的形式。

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

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

5. Massif
堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。

此外,lackey和nulgrind也会提供。Lackey是小型工具,很少用到;Nulgrind只是为开发者展示如何创建一个工具。我们就不做介绍了。

多线程检查工具的使用:

valgrind --tool=helgrind prog-and-args使用多线程调试工具

#include 
 
#include 
 
#include 
 
#include 
 
#include 
 
 
void * thread_worker1(void *args) ;
 
 
 
typedef struct worker_ctx_s
 
{
 
    int             shared_var  ;
 
    pthread_mutex_t lock ;
 
} worker_ctx_t ;
 
 
 
void *thread_worker1(void *args)
 
{
 
    worker_ctx_t    *ctx = (worker_ctx_t *)args ;
 
 
 
    if(!args)
 
    {
 
        printf("%s() get invalid arguments\n", __FUNCTION__) ; // __FUNCTION__ get function name
 
        pthread_exit(NULL) ;
 
    }
 
    printf("Thread worker1 [%ld] start running...\n", pthread_self()) ;
 
 
 
    /* 两次上锁导致死锁  */
 
    pthread_mutex_lock(&(ctx->lock)) ;
 
    pthread_mutex_lock(&(ctx->lock)) ;
 
 
 
    pthread_mutex_unlock( &ctx->lock ) ;
 
 
 
    sleep(1) ;
 
 
 
    printf("Thread worker1 exit...\n") ;
 
    pthread_exit(NULL) ;
 
    return NULL ;
 
}
 
 
 
int main(int argc, char **argv)
 
{
 
    worker_ctx_t    worker_ctx ;
 
    pthread_t       tid ;
 
    pthread_attr_t  thread_attr ;
 
 
    worker_ctx.shared_var = 1000 ;
    pthread_mutex_init(&worker_ctx.lock, NULL) ;
 
 
 
    if ( pthread_attr_init(&thread_attr) != 0 )
    {
        printf("pthread_attr_init() failed: %s\n", strerror(errno)) ;
        return -1 ;
    }
 
    if ( pthread_attr_setstacksize( &thread_attr, 1024*120) != 0 )
    {
        printf("pthread_setstacksize() failure: %s\n", strerror(errno) ) ;
        return -2 ;
    }
 
    if ( pthread_attr_setdetachstate(&thread_attr,  PTHREAD_CREATE_DETACHED) != 0 )
    {
        printf("pthread_attr_setdetachstate() error: %s\n", strerror(errno)) ;
        return -3 ;
    }
 
    /*    Create thread    */
 
    pthread_create(&tid, &thread_attr,  thread_worker1, &worker_ctx);
 
 
    if ( pthread_attr_destroy(&thread_attr) != 0 )
 
    {
        printf("pthread_attr_destroy() failed :%s\n", strerror(errno)) ;
        return -4 ;
    }
 
    sleep(5) ;
    return 0 ;
}

wyj@wyj-virtual-machine:~/c_code$ gcc -g valgrind_test_helgrand.c -o valgrind_test_helgrand -lpthread

wyj@wyj-virtual-machine:~/c_code$ valgrind --tool=helgrind ./valgrind_test_helgrand

63432 Helgrind, a thread error detector

63432 Copyright © 2007-2017, and GNU GPL’d, by OpenWorks LLP et al.

63432 Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info

63432 Command: ./valgrind_test_helgrand

程序打印的消息

Thread worker1 [67376896] start running…

63432 —Thread-Announcement------------------------------------------

两个线程被创建

63432 Thread #2 was created

63432 at 0x5158FFE: clone (clone.S:74)

63432 by 0x4E44199: do_clone.constprop.3 (createthread.c:75)

63432 by 0x4E458BA: create_thread (createthread.c:245)

63432 by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (pthread_create.c:611)

63432 by 0x4C31CBA: pthread_create_WRK (hg_intercepts.c:427)

63432 by 0x4C32D98: pthread_create@* (hg_intercepts.c:460)

63432 by 0x400CA2: main (valgrind_test_helgrand.c:84)

63432

63432 ----------------------------------------------------------------

尝试重新锁定本身已持有的非递归锁

63432 Thread #2: Attempt to re-lock a non-recursive lock I already hold

63432 at 0x4C2F259: mutex_lock_WRK (hg_intercepts.c:899)

63432 by 0x4C3317D: pthread_mutex_lock (hg_intercepts.c:925)

63432 by 0x400B5C: thread_worker1 (valgrind_test_helgrand.c:44)

63432 by 0x4C31EAE: mythread_wrapper (hg_intercepts.c:389)

63432 by 0x4E45183: start_thread (pthread_create.c:312)

63432 by 0x515903C: clone (clone.S:111)

锁之前已经获取过

63432 Lock was previously acquired

63432 at 0x4C2F320: mutex_lock_WRK (hg_intercepts.c:909)

63432 by 0x4C3317D: pthread_mutex_lock (hg_intercepts.c:925)

63432 by 0x400B4C: thread_worker1 (valgrind_test_helgrand.c:43)

63432 by 0x4C31EAE: mythread_wrapper (hg_intercepts.c:389)

63432 by 0x4E45183: start_thread (pthread_create.c:312)

63432 by 0x515903C: clone (clone.S:111)

63432

63432 ----------------------------------------------------------------

退出线程时任保持一个锁

63432 Thread #2: Exiting thread still holds 1 lock

63432 at 0x4E4BF1C: __lll_lock_wait (lowlevellock.S:135)

63432 by 0x4E47648: _L_lock_909 (pthread_mutex_lock.c:151)

63432 by 0x4E4746E: pthread_mutex_lock (pthread_mutex_lock.c:79)

63432 by 0x4C2F2BB: mutex_lock_WRK (hg_intercepts.c:902)

63432 by 0x4C3317D: pthread_mutex_lock (hg_intercepts.c:925)

63432 by 0x400B5C: thread_worker1 (valgrind_test_helgrand.c:44)

63432 by 0x4C31EAE: mythread_wrapper (hg_intercepts.c:389)

63432 by 0x4E45183: start_thread (pthread_create.c:312)

63432 by 0x515903C: clone (clone.S:111)

63432

63432

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

63432 the cost of reduced accuracy of conflicting-access information

63432 For lists of detected and suppressed errors, rerun with: -s

63432 ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 26 from 25)

你可能感兴趣的:(测试工具)