valgrind使用介绍
一、valgrind 安装步骤(linux)
#下载 wget http://valgrind.org/downloads/valgrind-3.14.0.tar.bz2
#解压 tar xvf valgrind-3.14.0.tar.bz2
#进入指定目录 cd valgrind-3.14.0/
#指定路径 ./configure --prefix=/home/yuanzhihong/valgrind/valgrind-3.14.0
make
make install #若安装不成功,重新make时,记得make clean
#检查是否安装成功
cd bin
./valgrind --version
#配置环境变量 vim ~/.bashrc
#将bin文件夹的路径放置.bashrc文件最后
#使改变生效 source ~/.bashrc
至此,完成valgrind的安装。
二、 valgrind工具介绍
- Memcheck是内存错误检测器。它可以帮助您使程序,尤其是用C和C ++编写的程序更加正确。
- Cachegrind是一个缓存和分支预测探查器。它可以帮助您使程序运行更快。
- Callgrind是一个生成调用图的缓存分析器。它与Cachegrind有一些重叠,但也收集了Cachegrind没有的一些信息。
- Helgrind是线程错误检测器。它可以帮助您使多线程程序更正确。
- DRD还是线程错误检测器。它类似于Helgrind,但是使用不同的分析技术,因此可能会发现不同的问题。
- Massif是堆分析器。它可以帮助您减少程序使用的内存。
- DHAT是另一种堆分析器。它可以帮助您了解模块寿命,模块利用率和布局效率低下的问题。
- BBV是一个实验性的SimPoint基本块矢量生成器。这对从事计算机体系结构研究和开发的人员很有用。
三、 编译程序
使用编译命令生成可执行程序
gcc -Wall main.c -g -o test
-Wall 表示生成警告信息
main.c 代表要编译的源文件
-g 生成调试信息
-o file 生成可执行文件
-O0 、-O1 、-O2 、-O3 编译器的优化选项的 4 个级别,-O0 表示没有优化, -O1 为默认值,-O3 优化级别最高。
注意:
(1)打开调试模式(gcc编译器的-g选项)。如果没有调试信息,即使最好的valgrind工具也将只能够猜测特定的代码是属于哪一个函数。打开调试选项进行编译后再用valgrind检查,valgrind将会给出具体到某一行的详细报告。
(2)关闭编译优化选项(比如-O2或者更高的优化选项)。这些优化选项可能会使得memcheck提交错误的未初始化报告,因此,为了使得valgrind的报告更精确,在编译的时候最好不要使用优化选项。
其他关于gcc的参数可参考https://www.runoob.com/w3cnote/gcc-parameter-detail.html
四、log内容组成介绍:
(1)版本信息
==28431== Memcheck, a memory error detector
==28431== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==28431== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==28431== Command: ./val
其中==中间的数字(28431)是valgrind的进程ID,也是program的进程ID,它们是同一个进程。
(2)错误信息
不同的命令出现不同的log内容,不同的错误输出也不同
(3)总结信息
==26787== HEAP SUMMARY:
==26787== in use at exit: 0 bytes in 0 blocks
==26787== total heap usage: 2 allocs, 2 frees, 73,728 bytes allocated
==26787==
==26787== All heap blocks were freed -- no leaks are possible
==26787==
==26787== For counts of detected and suppressed errors, rerun with: -v
==26787== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
五、 用valgrind运行程序,输出log
memcheck是valgrind tool的一种,是一个细粒度的的内存检查器。它可以检测以下问题:
1)使用未初始化的内存
测试代码
//类型1: 使用未初始化的栈空间
#include <iostream>
using namespace std;
int main()
{
int a;
cout << a + 3 <<endl;
return 0;
}
编译命令
g++ -g -o val 04.cpp
valgrind --log-file=04_1.log --track-origins=yes ./val
--track-origins=yes 表示开启“使用未初始化的内存”的检测功能,并打开详细结果。如果没有这句话,默认也会做这方面的检测,但不会打印详细结果。如:如果只使用1中的命令行,不会显示详细信息。
检测结果
Use of uninitialised value of size 8 #计算出未初始化的空间大小,不过计算错了
==26787== at 0x4F4462E: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==26787== by 0x4F44B53: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==26787== by 0x4F51074: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==26787== by 0x1088A5: main (04.cpp:15)
==26787== Uninitialised value was created by a stack allocation #识别出未初始化的值使用栈空间
==26787== at 0x10888A: main (04.cpp:13) #使用栈空间,定位该函数的左括号位置
命令栏详细解读:
--track-origins=<yes|no> [default: no]
控制Memcheck是否跟踪未初始化值的来源。默认为no
设置yes为时,Memcheck会跟踪所有未初始化值的来源。然后,当报告未初始化的值错误时,Memcheck将尝试显示值的来源。
对于源自堆的未初始化值,Memcheck将显示堆的分配位置。
对于源自栈分配的未初始化值,Memcheck可以告诉您哪个函数分配了该值,它会向您显示该函数的左括号的位置。因此,应该仔细检查函数的所有局部变量是否已正确初始化。
性能:使Memcheck的速度减半,并将内存使用量至少增加100MB,甚至可能更多。
其他未初始化内存示例可参考:
http://windmissing.github.io/linux/2016-02/valgrind-memcheck-uninitialized.html
2)内存泄漏
内存泄漏是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
测试代码
#include <iostream>
using namespace std;
int main()
{
int *p = new int;
return 0;
}
编译命令
g++ -g -o memleak 05.cpp
valgrind --log-file=05_1.log --leak-check=full ./memleak
检测结果
==29197== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29197== at 0x4C3042A: operator new(unsigned long) (vg_replace_malloc.c:334)
==29197== by 0x10879B: main (05.cpp:13) #详细错误信息,定位到行号
命令栏详细解读:
--leak-check=<no|summary|yes|full>[default: summary]
- --leak-check 指定如何报告内存泄漏(memcheck能检查多种内存使用错误,内存泄漏是其中常见的一种),可选值有:
no 不报告
summary 显示简要信息,有多少个内存泄漏。summary是缺省值。
yes 和 full 显示每个泄漏的内存在哪里分配。
--show-leak-kinds=<set> [default: definite,possible]
- show-leak-kinds 配合内存泄漏使用,指定显示内存泄漏的类型的组合。类型包括definite, indirect, possible,reachable。
- 也可以指定all或none。
其他未初始化内存示例可参考:
http://windmissing.github.io/linux/2016-02/valgrind-memcheck-memleak.html
3)使用malloc/new/new[]和free/delete/delete[]不匹配
http://windmissing.github.io/linux/2016-02/valgrind-memcheck-mismatch.html
4)src和dst的重叠
5)读/写已经被释放的内存
http://windmissing.github.io/linux/2016-02/valgrind-memcheck-deleted.html
6)读/写内存越界
7)读/写不恰当的内存栈空间
五、Memcheck 命令行选项解读
valgrind --log-file=03_8.log --tool=memcheck ./test
- --log-file 报告文件名。如果没有指定,输出到stderr。
- --tool=memcheck 指定Valgrind使用的工具。Valgrind是一个工具集,包括Memcheck、Cachegrind、Callgrind等多个工具。memcheck是默认项。
valgrind ./test #通用命令
其他命令行使用方法
参考链接:https://www.valgrind.org/docs/manual/mc-manual.html
definitely lost:内存没有被释放,且没有任何指针指向这里。肯定泄漏了。报告给出的堆栈是内存被分配时的调用堆栈,它可以基本明确内存是由什么业务逻辑创建的。
still reachable:是说内存没有被释放,尽管如此仍有指针指向,内存仍在使用中,这可以不算泄露。(程序退出时仍在工作的异步系统调用?)
possibly lost:是说可能有泄漏,一般是有二级指针(指针的指针)等复杂情况不易于追踪时出现。
suppressed:统计了使用valgrind的某些参数取消了特定库的某些错误,会被归结到这里
- 碎片化 | 第四阶段-40-Struts组件分类讲解-视频
- nginx location配置
- 碎片化 | 第四阶段-41-struts2字节流生成验证码-视频
- Python|模块,包,标准模板
- 人脸识别应用之“变脸”
- 碎片化 | 第四阶段-32-Struts2列表展示-视频
- Angularjs中UI Router超级详细的教程{{下}}
- 碎片化 | 第四阶段-33-Struts2-Spring整合环境概述讲解-视频
- 碎片化 | 第四阶段-34-Struts2-Spring重构项目案例-视频
- Python|高阶函数
- OpenCV特征点检测——ORB特征
- 智能图片压缩-腾讯智图
- 理解javascript闭包前,先理解作用域链
- 图片加速 WebP格式
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java注解详细总结
- 文档驱动 —— 表单组件(六):基于AntDV的Form表单的封装,目标还是不写代码
- 这就是你日日夜夜想要的docker!!!---------Docker资源控制--Cgroup
- 2020-09-26:请问rust中的&和c++中的&有哪些区别?
- python在Keras中使用LSTM解决序列问题
- python使用MongoDB,Seaborn和Matplotlib文本分析和可视化API数据
- 用于NLP的Python:使用Keras进行深度学习文本生成
- 用Python的Numpy求解线性方程组
- python用于NLP的seq2seq模型实例:用Keras实现神经机器翻译
- 使用Python和Keras进行主成分分析、神经网络构建图像重建
- python使用Flask,Redis和Celery的异步任务
- 在R语言中进行缺失值填充:估算缺失值
- Docsify 如何添加目录列表
- Dubbo日志链路追踪TraceId选型
- 重温C++的设计思想