上一个任务是利用valgrind的中的memcheck工具,将其加入到CI中。折腾了很久,大概一个月吧,最后由于非技术原因就hang在那了。这些都是题外话,现在讲讲valgrind本身。
valgrind中的很多配置具体的功能,官网上的,各路博客上转载的,已经说的很明白了。我这里说些要注意的,在使用中会遇到的,在官方文档中可能会被忽略的小心得。
1,生成supp文件
supp文件可以定义valgrind的检查过滤规则。如果你确实用过valgrind,你会发现其对内存的检查非常严厉,很容易存在误报(其实也不是误报,有时候那些错误只是你不关注的),尤其是对于libc中的malloc与free(好像还有new和delete,另外这个是个很tricky的地方,按照文档的意思是,libc里面malloc时,会额外分配一点内存用于某些事情来保证malloc的工作,而这些额外的内存不会被free释放掉,因为当线程释放的时候,linux内核会将这些额外的内存给释放了,从而内存检测工具的检查会被影响)以及一些其他的库(比如ACE?)。为了消除这些干扰信息,你需要生成supp文件。最简单的办法就是在启动valgrind的时候加上选项
--gen-suppressions=all,
再将生成的规则复制出来。当然,这不是一个聪明的办法。最好是将生成的结果整理一下,将多个相似的整理成一条。可以参考官方文档
suppressing errors
2,对程序的影响
如果你编写的只是小型程序,你可以不关注这一部分。但如果是大型程序(尤其对性能有要求的)或者是多线程程序(大型程序应该都这样吧),你的程序会工作起来后有些不同。第一,变的非常非常慢。valgrind模拟的一个软CPU,将可执行程序运行在其中。所以效率很低,速度慢很多,而且,valgrind的是单线程的(应该是),它会将你程序的所有线程统一管理起来,其实就是强制串行起来执行。所以你一定要明白这一点,用valgrind跑你的程序时,如果testcase挂掉了,看看是不是和性能有关的那些。
另外,请注意,64位的valgrind,不能执行32位的程序。这一点我没有严格验证过,也可能是版本没有更新的原因,至少在我调试时,64位的rhel系统下,产品的64位的程序会创建2个32位的子进程,然后挂在那里,没有错误也没有警告。
3,多进程追踪
如果你只是一个单一的小程序,不用开子进程,valgrind挺好用的。如果你要用valgrind去追踪多进程程序中的内存泄露,就有点繁琐了。有几个选项要特别注意。
--trace-children=yes 这个是必须的,打开追踪子进程
--log-file=<filename> --xml-file=<filename> 文本格式报告和xml格式报告的报告名称,推荐使用%p_log.memcheck之类的名字,%p会被valgrind转义成进程号,这样每一个进程都拥有一份独立的报告。
--child-silent-after-fork=yes 这个看情况,如果不打开的话,报告会更详细,错误定位可能会更精准,但是多份报告会混杂在一起,会直接破坏xml格式的报告
--trace-children-skip=patt1,patt2,... --trace-children-skip-by-arg=patt1,patt2,... 如果不使用这个,valgrind会追踪所有子进程,哪怕这个进程是java的。所以对应的,你需要让valgrind过滤一些子进程,--trace-children-skip是根据exec的file/path中的字符串匹配来过滤,--trace-children-skip-by-arg是根据exec的argv参数来过滤。没有正则表达式,只有*,?匹配两个符号可用。
另外,对于被执行程序而言,valgrind是other权限组的,所以记得更改执行权限。然后valgrind的报告会生成在,启动valgrind时用户所在的目录处。子进程的报告会生成在子进程程序所在目录。例如如果java在/bin/下,这报告会生成在/bin/里。但如果valgrind没有su权限,则报告会无法生成。
4,报告结果显示
其实valgrind的报告结果是很详细的。但是不要认为那些开发team愿意去一条条阅读valgrind的内存错误结果报告。所以,图形化显示结果是很重要的。幸运的是,Jenkins中已经包含了valgrind插件,而且非常好用。
安装valgrind插件:进入系统管理,插件管理中,在可选插件中搜索valgrind,然后安装即可。
配置valgrind插件:插件的默认工作目录是Jenkins的工作目录,所以要显示结果需要将valgrind的报告结果复制入Jenkins的工作目录。这里需要的报告结果是xml格式的。Report Pattern: 设置检索报告的命名格式,一般生成的报告如果是
%p_log.memcheck,那么这里就设置为*_log.memcheck.
配置好之后,在配置的下方,会出现valgrind Results。当每次构建完成之后,点击进入后都可以看到当前内存错误数量的图表,以及每个错误的函数名、函数调用关系等。
arm-linux版本的
调试
工具
,可用来
调试
内存泄漏或段错误,个人感觉比gdb好用。免安装下载后直接解压根目录即可,解压及执行命令如下:
解压: tar -xzvf
valgrind
.tgz -C /
执行:
valgrind
./xxx
用C/C++开发其中最令人头疼的一个问题就是内存管理,有时候为了查找一个内存泄漏或者一个内存访问越界,需要要花上好几天时间,如果有一款
工具
能够帮助我们做这件事情就好了,
valgrind
正好就是这样的一款
工具
。
Valgrind
是一款基于模拟linux下的程序
调试
器和剖析器的软件套件,可以运行于x86, amd64和ppc32架构上。
valgrind
包含一个核心,它提供一个虚拟的CPU运行程序,还有一
Valgrind
可以帮助我们初步检测代码中存在的内存泄露、死锁等常见问题。将
Valgrind
与Jenkins结合使用,再配合SCM、编译构建等步骤,可以做到流程自动化,帮助开发者在进入测试阶段之前就发现代码中的漏洞
Jenkins Pluginshttps://plugins.jenkins.io/Jenkins插件下载地址
Index of /download/plugins (jenkins-ci.org)http://updates.jenkins-ci.org/download/plugins/
在前面的文章中, 我们简单了解了
valgrind
工具
的用途以及安装, 以便大家能进行实际操作。 在本文中, 我们通过实例来看看如何利用
valgrind
来定位内存泄漏问题。 先看程序:
#include <stdio.h>
#include <stdlib.h>
char* getMemory()
char *p = (char *)malloc(30);
return p;
int main()
char *p = getMemory();
p = NULL;
return 0
看标题来说这应该是一篇教程式文章,但为了突出“玄幻”二字,我们不讲细节只讲过程,在过程中体会解决问题的方式和方法,以及避免一些我在这个过程中绕的弯路,如果想找
工具
的详细使用方法可以去参考文章中翻一翻,有几篇文章写的真不错,可以仔细看看...
需要注意的是,memcheck会加入代码检查每一片内存的访问和进行值运算,导致整体代码大小至少增加12倍,运行速度比平时慢25-50倍,所以使用
valgrind
时,保证机器环境有足够多的内存,如果进程本身启动内存有十几G,那用
valgrind
启动程序时,一般启动特别慢,可能1h才能启动程序。你的程序可能,至少在原则上,应该在退出前释放这些内存块。这些有指针指向的内存块和没有指针指向的内存块,或者只有内部指针指向的块,都可能产生内存泄露,因为实际上没有一个指向块起始的指针可以拿来释放,即使你想去释放它。