3. C++内存泄露扫描利器--valgrind

一. 简述valgrind是什么,为何能进行内存泄露

valgrind是一个程序调试及性能分析的工具集,涵盖memcheck, cachegrind,helgrind,callgrind,启动valgrind时通过--tool来指定具体要调用的工具。不论使用哪个工具,通过valgrind来启动程序时都会取得对程序的控制权,从关联库中读取调试信息。然后在valgrind核心提供的虚拟CPU上运行程序,根据选择的工具处理代码,该工具会向代码中植入检测代码,并把这些代码作为最终代码返回给valgrind核心,最后valgrind核心运行这些代码。

我们最常用valgrind进行内存泄露检查,通过--tool = memcheck --leak-check=yes指定。需要注意的是,memcheck会加入代码检查每一片内存的访问和进行值运算,导致整体代码大小至少增加12倍,运行速度比平时慢25-50倍,所以使用valgrind时,保证机器环境有足够多的内存,如果进程本身启动内存有十几G,那用valgrind启动程序时,一般启动特别慢,可能1h才能启动程序。或者,valgrind根本就拉不起来程序,此时,需要修改程序的相关配置参数,想办法将程序启动的进程内存减小。

二.编译程序时的注意

1. 编译时,打开调试模式(gcc编译器的-g选项)。

2. 编译时,关闭编译优化选项。一些编译优化选项(比如-O2或者更高的优化选项),可能会使得memcheck提交错误的未初始化报告,因此,为了使得valgrind的报告更精确,在编译的时候最好不要使用优化选项。

3. 如果程序有对tcmalloc编译依赖的话,需要将tcmalloc从编译依赖中去掉,否则valgrind扫描可能会遗漏一些报警信息。

4. 当检查的是C++程序的时候,还应该考虑另一个选项 -fno-inline。它使得函数调用链很清晰,这样可以减少你在浏览大型C++程序时的混乱。比如在使用这个选项的时候,用memcheck检查openoffice就很容易。当然,你可能不会做这项工作,但是使用这一选项使得valgrind生成更精确的错误报告和减少混乱。

三. valgrind下载 & 安装

---> 下载:wget http://www.valgrind.org/downloads/valgrind-3.8.1.tar.bz2

目前最新的版本是:Release 3.12.0 20 October 2016

---> 解压:bzip2 -d valgrind-3.8.1.tar.bz2; tar -xvf valgrind-3.8.1.tar

---> 安装: cd valgrind-3.8.1; ./configure --prefix=/home/work/tools/valgrind-3.8.1.install;make;make install

安装好后在valgrind-3.8.1.install目录里有: bin, lib, include, share 4个子目录

---> 确认是否安装正确:valgrind --version

---> 编辑/etc/profile,将valgrind工具加入PATH,再source /etc/profile,这样每次使用时都是新安装的valgrind

四、valgrind memcheck选项

参见手册http://www.valgrind.org/docs/manual/mc-manual.html

valgrind的选项非常的多,可以参考翻译手册中的说明进行选用,下面列出几个比较常用的:

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

Purpose : 当这个选项打开时,会当客户程序结束时查找内存泄露。如果设置为summary,Valgrind会报告有多少内存泄露发生了。如果设置为full或yes,Valgrind给出每一个独立的泄露的详细信息。

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

Purpose :在做内存泄漏检查时,确定memcheck将怎么样考虑不同的栈是相同的情况。当设置为low时,只需要前两层栈匹配就认为是相同的情况;当设置为med,必须要四层栈匹配,当设置为high时,所有层次的栈都必须匹配。

注意--leak-resolution= 设置并不影响memcheck查找内存泄漏的能力。它只是改变了结果如何输出。

Option: --show-reachable=yes|no  [default no]

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

Option: -v

Purpose : 显示详细信息。在各个方面显示你的程序的额外信息,例如:共享对象加载,使用的重置,执行引擎和工具的进程,异常行为的警告信息。重复这个标记可以增加详细的级别。

Option : -fno-inline

Purpose : 当检查的是C++程序的时候,可考虑这个选项-fno-inline。它使得函数调用链很清晰

Option : --max-stackframe=[default: 2000000]

Purpose : 栈的最大值,默认2000000。如果栈指针的偏移超过这个数量,valgrind则会认为程序是切换到了另外一个栈执行。

五. 内存泄露扫描过程

---> 程序启动(如果程序本身内存十几个G,启动非常慢,可能1h多才启动):

 nohup valgrind--tool=memcheck --leak-check=full --show-reachable=yes

--max-stackframe=8000000 --log-file=./valgrind.log [程序启动命令] &

---> 判断程序是否启动成功:

搜索程序端口是否被监听来判断程序是否被valgrind拉起

netstat -anlp|grep 9600|grep LISTEN   ##如果进程名是valgrind,则表示程序已经在valgrind环境中启动成功。

---> 给程序放一些请求,请求尽可能覆盖到程序的各个分支

---> 程序优雅退出,不要让服务在valgrind环境里core掉了。尽量服务有捕获kill信号能力,一般kill -9 pid会导致服务core掉。

---> 退出等待个几分钟,让valgrind收集退出信息输出到valgrind.log。最后分析valgrind.log

六. valgrind.log 报告分析

见手册http://www.valgrind.org/docs/manual/mc-manual.html ,关注关注definitely lost和possible lost处可能的内存泄露。

1)首先搜关键字『LEAK SUMMARY』,看『definitely lost』对应是否有值,如果不为0,肯定有内存泄露。

2)如果有内存泄露,往上搜报告中『definitely lost in loss』的报警处,对照程序代码一一排查。

3)常见内存泄露警告

---> a. Illegal read / Illegal write errors

已释放后的内存进行读/写或数组的越界访问等,valgrind报告程序在尝试读写非法内存,造成的后果是程序易发生segmentation fault(吐core)风险。

Invalid write of size X,访问超出了范围的内存,试图从该内存读取数据

---> b. Use of uninitialised values

检测使用未初始化变量,可以检测在条件判断语句中使用未初始化变量,因此应该养成在声明变量时就进行初始化的习惯

Conditional jump or move depends on uninitialised value(s)

---> c. When a heap block is freed with an inappropriate deallocation function

使用不正确的方法释放内存,比如new/delete , malloc/free使用混淆了,new分配的地方用free释放了

Mismatched free() / delete / delete []

---> d. Illegal frees

重复内存释放,比如2次使用free释放同一块内存

Invalid free() / delete / delete[]

---> e. Overlapping source and destination blocks

针对C语言常见的memcpy, strcpy, strncpy, strcat, strncat拷贝类函数,出现源串和目标串地址重叠

Source and destination overlap in memcpy(0xbffff294, 0xbffff280, 21)

---> f. Fishy argument values

所有内存分配类函数在分配内存时,都会传入一个内存分配大小的数,如果你传入的数大于机器所能分配的最大数时,如64位机器上,你传入的size大于了2**63

Argument 'size' of function malloc has a fishy (possibly negative) value: -3

---> g. Leak detecion

HEAP SUMMARY:  

如果指定--show-reachable=yes,在程序退出时memcheck会收集reachable and indirectly lost blocks

LEAK SUMMARY:

memcheck会记录由malloc/new等函数创建的所有的heap blocks,因此在程序退出时,memcheck能够知道哪些block没有free。如下:

definitely lost: 4 bytes in 1 blocks

indirectly lost: 0 bytes in 0 blocks

possibly lost: 0 bytes in 0 blocks

still reachable: 95 bytes in 6 blocks

definitely lost:如果一个block在程序在退出后,memcheck找不到指向它的pointer,一般是由于在代码中对该block没有free造成的,要重点关注。

possibly lost:在程序退出时,memcheck发现仍有 interior pointer(如果一个pointer指向一个block的中间某个位置)指向一个block,那么该block被认为是possibly lost。

still reachable:如果memcheck发现仍有start pointer指向一个block,那么该block就是still reachable。

4)valgrind不能查出哪些错误?

valgrind不对静态数组(分配在栈上)进行边界检查。如果在程序中声明了一个数组:

int main()

{

char x[10];

x[11] = ´a´;

}

valgrind则不会警告你,出于测试目的,你可以把数组改为动态在堆上分配的数组,这样就可能进行边界检查了。这个方法好像有点得不偿失的感觉。

七. 安装或使用中踩得各种坑

1)valgrind: failed to start tool 'memcheck' for platform 'amd64-linux'

解决办法:

该错误是valgrind启动时,无法找到相关工具文件,有可能是安装好后相关lib的path未设置,也有可能是一开始安装就有问题。解决办法如下:

如果已经安装成功,试一下导出VALGRIND_LIB路径,用法如下(假设valgrind已经被安装到/home/work/tools/valgrind目录):##亲测有效##

export VALGRIND_LIB=/home/work/tools/valgrind3.8.1/lib/valgrind

2)valgrind --version报错

valgrind: mmap((nil), 134512640) failed during startup.

valgrind: is there a hard virtual memory limit set?

解决办法:

见下,版本太老,里边有bug,重新安装一下较新版本应该能解决。https://twiki.cern.ch/twiki/bin/view/LHCb/CodeAnalysisTools

3)vg_alloc_ThreadState: no free slots available

Increase VG_N_THREADS, rebuild and try again.

valgrind: the 'impossible' happened:

VG_N_THREADS is too low

解决办法:

a) 修改VG_N_THREADS和NTHREADS的值,安装用的是3.8.1版本,默认VG_N_THREADS是500,现在改为5000,同时NTHREADS由498改成4998。

include/pub_tool_threadstate.h: #define VG_N_THREADS 5000

./memcheck/tests/err_disable4.c: #define NTHREADS 4998  // VG_N_THREADS - 2

b) 按照1进行重新安装。

4) Valgrind: FATAL: VG_N_SEGMENTS is too low.

解决办法:

VG_N_SEGMENTS默认是5000。修改coregrind/m_aspacemgr/aspacemgr-linux.c: VG_N_SEGMENTS从5000改到50000,VG_N_NAME从1000改到5000。

按照1进行重新安装。

5)valgrind.log报告中,在definitely lost的代码处全是?????全写花了,看不出具体泄露的是在哪一行代码

解决办法:

加上-g,打开调试信息重新编译程序;

valgrind扫描时加上--show-reachable=yes


参考:

1. http://www.xlgps.com/article/216977.html

2. 如何使用Valgrind memcheck工具进行C/C++的内存泄漏检测

3. 用Valgrind查找内存泄漏和无效内存访问

4. valgrind介绍

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,131评论 2 34
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 使用MsLeak以及Instument调试解决iOS内存泄露 虽然iOS 5.0版本之后加入了ARC机制,由于相互...
    慧众rodman阅读 2,057评论 0 11
  • 沟通,我认为是多方面多元化的。广义上讲,沟通体现在生活的方方面面。阅读,是与作者的沟通。旅行,是与大自然...
    你说你傻不傻y阅读 596评论 0 0
  • 说不清的南城旧事,道不明的北郡乱铃。 你问我:走过了那座奈何桥,喝干了那碗孟婆汤,你还会抱着今天的执念吗?我笑笑,...
    木木天空阅读 125评论 0 0