参考文章
Valgrind学习总结
应用 Valgrind 发现 Linux 程序的内存问题
Valgrind介绍
Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其他工具;而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。Valgrind的体系结构如下图所示:
Valgrind包括如下一些工具:
- Memcheck。这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。
- Callgrind。它主要用来检查程序中函数调用过程中出现的问题。
- Cachegrind。它主要用来检查程序中缓存使用出现的问题。
- Helgrind。它主要用来检查多线程程序中出现的竞争问题。
- Massif。它主要用来检查程序中堆栈使用中出现的问题。
- Extension。可以利用core提供的功能,自己编写特定的内存调试工具。
Valgrind的使用
编译命令:
gcc hello.c -g -o hello
🐖 编译时加上-g
选项可以定位到代码行
🐖 编译优化选项请选择O0
,虽然这会降低程序的执行效率
调试命令:
valgrind -v --log-file=valgrind.log --tool=memcheck --leak-check=full --show-mismatched-frees=yes ./hello
说明:加--log-file=valgrind.log
会在当前目录下生成日志文件,日志不会在终端打印
检查内存错误:
valgrind --leak-check=full --show-reachable=yes --trace-children= yes ./hello
其中--leak-check=full
指的是完全检查内存泄漏,--show-reachable=yes
是显示内存泄漏的地点,--trace-children=yes
是跟入子进程。
如果您的程序是会正常退出的程序,那么当程序退出的时候valgrind自然会输出内存泄漏的信息。
如果您的程序是个守护进程,那么也不要紧,我们 只要在别的终端下杀死memcheck进程(因为valgrind默认使用memcheck工具,就是默认参数—tools=memcheck
):
killall memcheck
这样我们的程序(./hello)就被kill了。
检查代码覆盖和性能瓶颈:
我们调用valgrind的工具执行程序:
valgrind --tool=callgrind ./sec_infod
会在当前路径下生成callgrind.out.pid(当前生产的是callgrind.out.19689),如果我们想结束程序,可以:
#killall callgrind
然后我们看一下结果:
#callgrind_annotate --auto=yes callgrind.out.19689 >log
#vim log
callgrind_annotate
可以把这个文件的内容转化成可读的形式。
一般像下面这样调用Valgrind:
频率较高的常用选项
1、要求用 memcheck这个工具对程序进行分析
-–tool=[default: memcheck]
-–tool=memcheck
2、 将输出的信息写入到filename.PID
的文件里,PID是运行程序的进行ID
–log-file=filename
3、指定就输出到 filename文件
–log-file-exactly=filename
4、把输出信息发送到网络中指定的IP:PORT中 去
–log-socket=IP:PORT
5、要求对leak给出详细信息
–leak-ckeck=yes
6、完全检查内存泄漏
–leak-check=full
7、如果为yes, valgrind会在每发现一个错误便停下让用户做选择是继续还是退出
–gen-suppressions=[default: no]
用法: valgrind [options] prog-and-args [options]
:
常用选项,适用于所有Valgrind工具
-tool=[default: memcheck]
最常用的选项。运行 valgrind中名为toolname的工具。默认memcheck。
h --help 显示帮助信息.
v –verbose 更详细的信息, 增加错误数统计。
-version 显示valgrind内核的版本,每个工具都有各自的版本。
q –quiet 安静地运行,只打印错误信息。
-trace-children=no|yes 跟踪子线程 [no]
-track-fds=no|yes 跟踪打开的文件描述[no]
-time-stamp=no|yes 增加时间戳到LOG信息 [no]
-log-fd= [number] 输出LOG到描述符文件 [2=stderr]
-log-file=[file] 将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID
-log-file-exactly=[file] 输出LOG信息到 file
-log-file-qualifier=[VAR] 取得环境变量的值来做为输出信息的文件名。 [none]
-log-socket=ipaddr:port 输出LOG到socket ,ipaddr:port
LOG信息输出
-xml=yes
将信息以xml格式输出,只有memcheck可用
--xml-file=mem.memcheck
指定xml报告输出路径和名称
-num-callers=<number>
show callers in stack traces [12]
定义在堆栈追踪过程中显示的最大嵌套调用数
-error-limit=no|yes 如果太多错误,则停止显示新错误 [yes]
-error-exitcode= 如果发现错误则返回错误代码 [0=disable]
-db-attach=no|yes 当出现错误,valgrind会自动启动调试器gdb。[no]
-db-command= 启动调试器的命令行选项[gdb -nw %f %p]
适用于Memcheck工具的相关选项:
-leak-check=no|summary|full [default: summary]
Leak是指,存在一块没有被引用的内存空间,或没有被释放的内存空间,如 summary,只反馈一些总结信息,告诉你有多少个malloc ,多少个free 等;如果是full 将输出所有的leaks,也就是定位到某一个malloc/free 。
-leak-resolution=low|med|high
how much bt merging in leak check [default: low]
-show-reachable=[default: no]
如果为 no,只输出没有引用的内存leaks,或指向 malloc返回的内存块中部某处的leaks ;为yes,检测控制范围之外的泄漏,比如全局指针、static指针等
–undef-value-errors=[default: yes] 如果为 yes,memcheck将对无定义值错进行检查