一、valgrind简介

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

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在这里帮上了大忙。

memcheck 工具的常用选型

1、leak-check

--leak-check=<no|summary|yes|full> [default: summary]

用于控制内存泄漏检测力度。

no,不检测内存泄漏;

summary,仅报告总共泄漏的数量,不报告具体泄漏位置;

yes/full,报告泄漏总数、泄漏的具体位置。

2、show-reachable

--show-reachable=<yes|no> [default: no]

用于控制是否检测控制范围之外的泄漏,比如全局指针、static指针等。

3、undef-value-errors

--undef-value-errors=<yes|no> [default: yes]

用于控制是否检测代码中使用未初始化变量的情况。

4、其他选项

--log-file=filename 将结果输出到文件。

--log-socket=192.168.0.1:12345 输出到网络。

--trace-children=<yes|no> [default: no]

--track-fds=<yes|no> [default: no]

--log-fd=<number> [default: 2, stderr]

--xml=<yes|no> [default: no]

--num-callers=<number> [default: 12]

--show-below-main=<yes|no> [default: no]

内存检查选项:

--leak-check=<no|summary|yes|full> [default: summary]

当这个选项打开时,当客户程序结束时查找内存泄漏。内存泄漏意味着有用malloc分配内存块,但是没有用free释放,而且没有指针指向这块内存。这样的内存块永远不能被程序释放,因为没有指针指向它们。如果设置为summary,Valgrind会报告有多少内存泄漏发生了。如果设置为full或yes,Valgrind给出每一个独立的泄漏的详细信息。

--show-reachable=<yes|no> [default: no]

当这个选项关闭时,内存泄漏检测器只显示没有指针指向的内存块,或者只能找到指向块中间的指针。当这个选项打开时,内存泄漏检测器还报告有指针指向的内存块。这些块是最有可能出现内存泄漏的地方。你的程序可能,至少在原则上,应该在退出前释放这些内存块。这些有指针指向的内存块和没有指针指向的内存块,或者只有内部指针指向的块,都可能产生内存泄漏,因为实际上没有一个指向块起始的指针可以拿来释放,即使你想去释放它。

--leak-resolution=<low|med|high> [default: low]

在做内存泄漏检查时,确定memcheck将怎么样考虑不同的栈是相同的情况。当设置为low时,只需要前两层栈匹配就认为是相同的情况;当设置为med,必须要四层栈匹配,当设置为high时,所有层次的栈都必须匹配。对于hardcore内存泄漏检查,你很可能需要使用--leak-resolution=high和--num-callers=40或者更大的数字。注意这将产生巨量的信息,这就是为什么默认选项是四个调用者匹配和低分辨率的匹配。注意--leak-resolution= 设置并不影响memcheck查找内存泄漏的能力。它只是改变了结果如何输出。

--freelist-vol=<number> [default: 5000000]

当客户程序使用free(C中)或者delete(C++)释放内存时,这些内存并不是马上就可以用来再分配的。这些内存将被标记为不可访问的,并被放到一个已释放内存的队列中。这样做的目的是,使释放的内存再次被利用的点尽可能的晚。这有利于memcheck在内存块释放后这段重要的时间检查对块不合法的访问。这个选项指定了队列所能容纳的内存总容量,以字节为单位。默认的值是5000000字节。增大这个数目会增加memcheck使用的内存,但同时也增加了对已释放内存的非法使用的检测概率。

--workaround-gcc296-bugs=<yes|no> [default: no]

当这个选项打开时,假定读写栈指针以下的一小段距离是gcc 2.96的bug,并且不报告为错误。距离默认为256字节。注意gcc 2.96是一些比较老的Linux发行版(RedHat 7.X)的默认编译器,所以你可能需要使用这个选项。如果不是必要请不要使用这个选项,它可能会使一些真正的错误溜掉。一个更好的解决办法是使用较新的,修正了这个bug的gcc/g++版本。

--partial-loads-ok=<yes|no> [default: no]

控制memcheck如何处理从地址读取时字长度,字对齐,因此哪些字节是可以寻址的,哪些是不可以寻址的。当设置为yes是,这样的读取并不抛出一个寻址错误。而是从非法地址读取的V字节显示为未定义,访问合法地址仍然是像平常一样映射到内存。设置为no时,从部分错误的地址读取与从完全错误的地址读取同样处理:抛出一个非法地址错误,结果的V字节显示为合法数据。注意这种代码行为是违背ISO C/C++标准,应该被认为是有问题的。如果可能,这种代码应该修正。这个选项应该只是做为一个最后考虑的方法。

--undef-value-errors=<yes|no> [default: yes]

控制memcheck是否检查未定义值的危险使用。当设为yes时,Memcheck的行为像Addrcheck, 一个轻量级的内存检查工具,是Valgrind的一个部分,它并不检查未定义值的错误。使用这个选项,如果你不希望看到未定义值错误。

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

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

:~/Download$ tar -xjvf valgrind-3.15.0.tar.bz2

:~/Download$ cd valgrind-3.15.0/

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

:~/Download/valgrind-3.15.0$ ./configure

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

:~/Download/valgrind-3.15.0$ make

:~/Download/valgrind-3.15.0$ sudo make install

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

:~/Download/valgrind-3.15.0$ valgrind --version

valgrind-3.15.0

三、valgrind使用

1、内存泄漏

#include <stdio.h>
#include <stdlib.h>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的错误消息包含确切的行号。

:~/c_code$ gcc -g valgrind_test.c -o valgrind_test

正常运行

:~/c_code$ ./valgrind_test

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

:~/c_code$ valgrind --leak-check=yes ./valgrind_test

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

==62414== Memcheck, a memory error detector

==62414== Copyright (C) 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)

2线程锁

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>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 namepthread_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 ;
}

:~/c_code$ gcc -g valgrind_test_helgrand.c -o valgrind_test_helgrand -lpthread

:~/c_code$ valgrind --tool=helgrind ./valgrind_test_helgrand

==63432== Helgrind, a thread error detector

==63432== Copyright (C) 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)

valgrind小结相关推荐

  1. linux注入内存泄露,Linux 内存泄露小结

    本文仅限记录自己的一次 内存泄露追踪小记. 可能并不十分适用与大家的情况.而且方法也并不是很smart.仅做记录,能提供个思路更好. 一. 要问调试程序遇到什么问题最头疼, 内存泄露肯定能排在前几名里 ...

  2. 遇到一个valgrind自身的bug

    背景 公司C++项目代码使用了cppcheck做静态代码检查,也使用valgrind检查是否有内存泄漏问题.我多次强调要做到0警告,虽然有了CICD的Jenkins自动检查,也将结果通过邮件发给项目人 ...

  3. C/C++之内存调试工具GDB与Valgrind

    0 背景 写 C++的同学想必有太多和内存打交道的血泪经验了,常常被 C++的内存问题搅的焦头烂额.(写 core 的经验了)有很多同学一见到 core 就两眼一抹黑,不知所措了.笔者 入" ...

  4. 记一次使用Valgrind查找解决内存问题的玄幻旅程

    文章目录 前言 玄幻旅途 故事背景 初入泥潭 一片混沌 追根溯源 抽丝剥茧 大海捞针 祭出法宝 屏蔽无关 移形换位 再请法宝 风平浪静 若有所思 参考文章 前言 看题目来说这应该是一篇教程式文章,但为 ...

  5. 代码测试,调试与优化小结

    http://www.cppblog.com/cuijixin/default.html?page=8 代码测试.调试与优化的小结 by falcon<zhangjinw@gmail.com&g ...

  6. GJM :C++ 资源收集小结

    c++ 资源收集小结 阅读目录 标准库 框架 人工智能 异步事件循环 音频 生态学 压缩 并发性 容器 密码学 数据库 调试 游戏引擎 图形用户界面 图形 图像处理 国际化 Jason 日志 机器学习 ...

  7. valgrind基本功能介绍、基础使用方法说明

    1.Valgrind概述 Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合. Valgrind由内核(core)以及基于内核的其他调试工具组成.内核类似于一个框架(f ...

  8. Linux 命令(143)—— valgrind 命令

    文章目录 1.命令简介 2.命令格式 3.选项说明 4.常用示例 4.1 内存泄漏 4.2 内存越界 4.3 内存覆盖 4.4 使用未初始化的值 4.5 内存申请与释放函数不匹配 5.小结 参考文献 ...

  9. 用valgrind 检测内存错误

    用valgrind 检测内存错误 ---------------------------------------- 前言: -------------------------------------- ...

最新文章

  1. html5手机端的点击弹出侧边滑动菜单代码
  2. printf 指针地址_c语言入门 第十四章指针
  3. 数据库与数据库管理系统的关系
  4. android 响应类型,android – Retrofit 2 RxJava – Gson – “全局”反序列化,更改响应类型...
  5. JDBC中使用RowSet包装结果集
  6. 【飞秋】ASP.NET 之 常用类、方法的超级总结,并包含动态的EXCEL导入导出功能,奉上类库源码
  7. 理工科学生计算机要求,理工科学生
  8. Apache构建虚拟web主机
  9. mysql generator 命令_Mybatis使用命令生成逆向工程的方法
  10. PR转场预设 放大特效带有重影效果的PR视频转场预设
  11. Java笔记 - 黑马程序员_06(Stream,字节流,字符流,对象流(序列化流),属性集(Properties))
  12. 禅道 upgrade.php,禅道升级,添加钉钉通知
  13. 【转载】提问的智慧(How To Ask Questions The Smart Way)
  14. sohu_news搜狐新闻类型分类
  15. C# 把word转换成txt
  16. 缘系天涯,一枕残梦千里殇岁月沉积着忧伤:伤感日志
  17. springboot中的事务
  18. 爬虫 Pinterest 多个接口分析(uqPN4sH5tPPJ5727zfjVvg==)
  19. php漏洞 乌云,GitHub - grt1st/wooyun_search: 乌云公开漏洞、知识库搜索 search from wooyun.org...
  20. 文件翻译改名,将名称从中文翻译成英文的方法

热门文章

  1. python list除以_每日一课 | python判断奇数和偶数
  2. c语言怎么使用数组播放下一首音乐,【数组编程面试题】面试问题:c语言MP3播… - 看准网...
  3. 对接钉钉审批_钉钉审批对接是什么-和钉钉审批对接相关的问题-阿里云开发者社区...
  4. (SVN+SSH)搭建SVN并使用SSH进行免密拉取推送代码
  5. torch.Tensor常用数据操作汇总与自动求梯度
  6. 全网最新最全的jmeter+ant+jenkins 搭建接口自动化测试
  7. 模仿学习(GMM-GMR应用)
  8. html调用短信接口,.net短信接口调用示例(106短信通道)
  9. 一个人如何完成一整个网站的开发(推荐好文,看完绝对让你回味无穷)
  10. 中职学校计算机专业精品课,建设中职学校计算机应用基础精品课程之我见