C/C++内存泄露检查利器—valgrind

news2024/11/17 12:22:32

1、Valgrind概述

Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。

Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其他工具;而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。

2、工具下载安装

参考地址:https://www.valgrind.org/downloads/

安装:

tar –xf valgrind-3.17.0.tar.bz2
cd valgrind-3.17.0
./configure         // 运行配置脚本生成makefile文件,可以--help查看配置项,自行按需配置,比如修改编译工具、修改安装路径等
make
make install        //安装生成可执行文件,可执行文件的路径有参数--prefix指定,需要在PATH中添加环境变量;若不加参数--prefix指定,仅使用默认配置,则会自动关联

安装完后可以使用:

valgrind --help查看使用方法

3、使用基本选项

3.1 基本工具介绍

  • Memcheck。这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。

  • Callgrind。它主要用来检查程序中函数调用过程中出现的问题。

  • Cachegrind。它主要用来检查程序中缓存使用出现的问题。

  • Helgrind。它主要用来检查多线程程序中出现的竞争问题。

  • Massif。它主要用来检查程序中堆栈使用中出现的问题。

  • Extension。可以利用core提供的功能,自己编写特定的内存调试工具

3.2 常用选项

  1. 适用于所有Valgrind工具

–tool=< name > 最常用的选项。运行 valgrind中名为toolname的工具。默认memcheck。
-h --help 显示帮助信息。
–version 显示valgrind内核的版本,每个工具都有各自的版本。
-q --quiet 安静地运行,只打印错误信息。
-v --verbose 更详细的信息, 增加错误数统计。
–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
  1. LOG信息输出

–xml=yes 将信息以xml格式输出,只有memcheck可用
–num-callers=< number > show < numbe r> callers in stack traces [12]
–error-limit=no|yes 如果太多错误,则停止显示新错误? [yes]
–error-exitcode=< number > 如果发现错误则返回错误代码 [0=disable]
–db-attach=no|yes 当出现错误,valgrind会自动启动调试器gdb。[no]
–db-command=< command > 启动调试器的命令行选项[gdb -nw %f %p]
  1. 适用于Memcheck工具的相关选项:

–leak-check=no|summary|full 要求对leak给出详细信息? [summary]
–leak-resolution=low|med|high how much bt merging in leak check [low]
–show-reachable=no|yes show reachable blocks in leak check? [no]

更详细的使用信息详见帮助文件、man手册或官网:http://valgrind.org/docs/manual/manual-core.html

  1. 注意

(1)valgrind不会自动的检查程序的每一行代码,只会检查运行到的代码分支,所以单元测试或功能测试用例很重要;

(2)可以把valgrind看成是一个sandbox,通过valgrind运行的程序实际上是运行在valgrind的sandbox中的,所以,不要测试性能,会让你失望的,建议只做功能测试

(3)编译代码时,建议增加-g -o0选项,不要使用-o1、-o2选项

3.3 常用选项示例

–tool=< name > : use the Valgrind tool named < name > [memcheck]
–log-file=< file > : log messages to < file >

示例:

valgrind --tool=memcheck --log-file=log.txt --leak-check=yes  ./test

说明:使用memcheck工具对test程序进行包含内存泄漏的检查,并将日志保存到log.txt

4、Memcheck工具介绍

Memcheck是valgrind应用最广泛的工具,能够发现开发中绝大多数内存错误使用情况。此工具主要可检查以下错误

  • 使用未初始化的内存(Use of uninitialised memory)

  • 使用已经释放了的内存(Reading/writing memory after it has been free’d)

  • 使用超过malloc分配的内存空间(Reading/writing off the end of malloc’d blocks)

  • 对堆栈的非法访问(Reading/writing inappropriate areas on the stack)

  • 申请的空间是否有释放(Memory leaks – where pointers to malloc’d blocks are lost forever)

  • malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])

  • src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)

#include<iostream>
int main()
{
 int *pInt;
 std::cout<<"使用未初始化的内存";
 int a=*pInt;    //使用未初始化的内存
}

#include<iostream>
int main()
{
 int *pArray=(int *)malloc(sizeof(int) *5);
 std::cout<<"使用已经释放了的内存";
 free(pArray);
 pArray[0]=0;    //使用已经释放了的内存
}

#include<iostream>
int main()
{
 int *pArray=(int *)malloc(sizeof(int) *5);
 std::cout<<"使用超过malloc分配的内存空间";
 pArray[5]=5;    //使用超过malloc分配的内存空间
 free(pArray);
}

#include<iostream>
int main()
{
 int *pArray=(int *)malloc(sizeof(int) *5);
 std::cout<<"malloc缺少free";
}

#include<iostream>
int main()
{
 char a[10];
 for (char c=0; c < sizeof(a); c++)
 {
  a[c]=c;
 }
 std::cout<<"拷贝的src和dst存在重叠";
 memcpy(&a[4],&a[0],6);
}

注:程序有时会申请很多常驻节点,这些未释放的节点不应视为问题;

一般随着程序的运行,导致节点单向增加的malloc或new操作,视为内存泄漏

4.1 示例1

源码:

#include<iostream>
int main()
{
 int *pArray=(int *)malloc(sizeof(int) *5);
 std::cout<<"使用超过malloc分配的内存空间";
 pArray[5]=5;    //使用超过malloc分配的内存空间
 free(pArray);
}
12345678

编译:

g++ test1.cpp -g -o test1_g   //-g:让 memcheck 工具可以取到出错的具体行号

调试:

valgrind --leak-check=yes --log-file=1_g ./test1_g

生成日志文件1_g:

(1)当前程序(./test1_g)的进程号

(2)valgrind memcheck工具的license说明

(3)加载程序的运行方式

(4)父进程号,当前终端的进程

(5)检测到的错误信息

(6)堆栈摘要、小结,该例子中总共两次alloc、两次free,没有内存泄漏

(7) 检测到的错误数量,这里提示1个

4.2 示例2

#include<iostream>
int main()
{
 int *pArray=(int *)malloc(sizeof(int) *5);
 std::cout<<"使用已经释放了的内存";
 free(pArray);
 pArray[0]=0;    //使用已经释放了的内存
}

编译:

g++ test7.cpp -g -o test7_g   //-g:让 memcheck 工具可以取到出错的具体行号

调试:

valgrind --leak-check=yes --log-file=7_g ./test7_g

生成日志文件7_g:

(1)因为还是使用同一个终端,所以父进程还是8248

(2) 有两个非法的读、写错误

编译:

g++ test7.cpp -g -o test2_g_O2 -O2 

调试:

valgrind --leak-check=yes --log-file=7_g_O2 ./test7_g_O2

生成日志文件7_g_O2:

可以看到同样的程序,在加上-O2之后,pArray[0]=0;语句被优化掉了,所以没有被检测出来。

为了做到更严格的检测,编译时需要保证编译器没有做优化,即优化等级为-O0,gcc、g++默认就是采用-O0的,但是大部分实际设计都会在Makefile中添加-O1或者-O2参数,所以最好还是检查下。

4.3 Memcheck 报告输出文档整体格式总结

  1. copyright 版权声明

  2. 异常读写报告
    2.1 主线程异常读写

    线程A异常读写报告
    线程B异常读写报告

  3. 其他线程

  4. 堆内存泄露报告
    4.1 堆内存使用情况概述(HEAP SUMMARY)

    4.2 确信的内存泄露报告(definitely lost)

    4.3 可疑内存操作报告 (show-reachable=no关闭,打开:–show-reachable=yes)

    4.4 泄露情况概述(LEAK SUMMARY)

4.4 Memcheck 日志报告的基本格式

{问题描述}
at {地址、函数名、模块或代码行}
by {地址、函数名、代码行}
by …{逐层依次显示调用堆栈}
Address 0x??? {描述地址的相对关系}

4.5 memcheck包含的7类错误

  1. illegal read/illegal write errors
    提示信息:[invalid read of size 4]

  2. use of uninitialised values
    提示信息:[Conditional jump or move depends on uninitialised value]

  3. use of uninitialised or unaddressable values in system calls
    提示信息:[syscall param write(buf) points to uninitilaised bytes]

  4. illegal frees
    提示信息:[invalid free()]

  5. when a heap block is freed with an inappropriate deallocation function
    提示信息:[Mismatched free()/delete/delete[]]

  6. overlapping source and destination blocks
    提示信息:[source and destination overlap in memcpy(,)]

  7. memory leak detection
    ① still reachable
    内存指针还在还有机会使用或释放,指针指向的动态内存还没有被释放就退出了

    ② definitely lost
    确定的内存泄露,已经不能访问这块内存

    ③ indirectly lost
    指向该内存的指针都位于内存泄露处

    ④ possibly lost
    可能的内存泄露,仍然存在某个指针能够快速访问某块内存,但该指针指向的已经不是内存首位置

4.6 memcheck工具原理

Memcheck实现了一个仿真的CPU,被监控的程序被这个仿真CPU解释执行,该仿真CPU可以在所有的内存读写指令发生时,检测地址的合法性和读操作的合法性。

Memcheck 能够检测出内存问题,关键在于其建立了两个全局表。

  1. Valid-Value 表:

    对于进程的整个地址空间中的每一个字节(byte),都有与之对应的8 个bits;对于CPU 的每个寄存器,也有一个与之对应的bit 向量。这些bits 负责记录该字节或者寄存器值是否具有有效的、已初始化的值。

  2. Valid-Address 表

    对于进程整个地址空间中的每一个字节(byte),还有与之对应的1 个bit,负责记录该地址是否能够被读写。

    检测原理:

    当要读写内存中某个字节时,首先检查这个字节对应的A bit。如果该A bit显示该位置是无效位置,memcheck 则报告读写错误。

    内核(core)类似于一个虚拟的CPU 环境,这样当内存中的某个字节被加载到真实的CPU 中时,该字节对应的V bit 也被加载到虚拟的

    CPU 环境中。一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序输出,则memcheck 会检查对应的V bits,如果该值

    尚未初始化,则会报告使用未初始化内存错误。

简单来说

  1. 如何知道那些地址是合法的(内存已分配)?
    维护一张合法地址表(Valid-address (A) bits),当前所有可以合法读写(已分配)的地址在其中有对应的表项。该表通过以下措施维护:

    ① 全局数据(data, bss section)–在程序启动的时候标记为合法地址

    ② 局部变量–监控sp(stack pointer)的变化,动态维护

    ③动态分配的内存–截获 分配/释放 内存的调用:malloc, calloc, realloc, valloc, memalign, free, new, new[], delete and delete[]

    ④ 系统调用–截获mmap映射的地址

    ⑤ 其他–可以显示知会memcheck某地字段是合法的

  2. 如何知道某内存是否已经被赋值?

    ①维护一张合法值表(Valid-value (V) bits),指示对应的bit是否已经被赋值。因为虚拟CPU可以捕获所有对内存的写指令,所以这张表很容易维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/493048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android中的GPS开发

GPS简介 Gobal Positioning System&#xff0c;全球定位系统&#xff0c;是美国在20世纪70年代研制的一种以人造地球卫星为基础的高精度无线电导航的定位系统&#xff0c;它在全球任何地方以及近地空间都能够提供准确的地理位置、车行速度及精确的时间信息&#xff1b;它是具有…

2023年房地产抵押贷款研究报告

第一章 概述 房地产抵押贷款是一种以房地产为抵押品的贷款形式&#xff0c;包括个人和企业两种情况。个人房地产抵押贷款是指个人将名下房产作为抵押品向银行或其他金融机构申请贷款&#xff0c;而企业房地产抵押贷款则是指企业将自己名下的商业房产作为抵押品向金融机构申请贷…

202309读书笔记|《野性之美:非洲野生动物初窥》——走进自然界的野性之美

《野性之美: 非洲野生动物初窥》微读的一本书&#xff0c;图片居多&#xff0c;非常有视觉上的震撼。拍摄者也是我们孙姓的一员&#xff0c;孙长智。正如作者所说&#xff0c;与自然对话&#xff0c;你会感悟到生命之美、竞争之美、进化之美、和谐之美&#xff01; 我喜欢自然…

SPSS如何绘制常用统计图之案例实训?

文章目录 0.引言1.绘制简单条形图2.绘制分类条形图3.绘制分段条形图4.绘制简单线图5.绘制多重线图6.绘制垂直线图7.绘制简单面积图8.绘制堆积面积图9.绘制饼图10.绘制直方图11.绘制简单散点图12.绘制重叠散点图13.绘制矩阵散点图14.绘制三维散点图15.绘制简单箱图16.绘制分类箱…

【markdown工具配合图床】PicGo图床配置教程,一秒读懂配置

前言 看到这篇文章的大佬&#xff0c;我默认大家都会配置git&#xff0c;已经配置好ssh公钥。 此时你看到的这篇文章就是基于markdown工具&#xff08;VSCode&#xff0c;Typora&#xff09;编写的。 PicGo作为图床转换工具&#xff0c;并配合gitee作为图片服务器&#xff0…

java元注解和自定义注解的区别

Java的元注解和自定义注解是两个不同的概念。 元注解是Java内置的一组用于修饰其他注解的注解&#xff0c;包括Retention、Target、Inherited和Documented。它们可以控制被修饰的注解的保留策略、目标范围、是否继承等属性&#xff0c;并且可以在编写自定义注解时使用。 Retent…

国考省考结构化面试:综合分析题,社会现象(积极消极政策)、名言哲理(警句观点启示)、漫画反驳题等

国考省考结构化面试&#xff1a;综合分析题&#xff0c;社会现象&#xff08;积极消极政策&#xff09;、名言哲理&#xff08;警句观点启示&#xff09;、漫画反驳题等 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&…

【Java数据结构】优先级队列(堆)

优先级队列&#xff08;堆&#xff09; 概念模拟实现堆的概念堆的存储方式堆的创建向下调整堆的创建建堆的时间复杂度 堆的插入和删除堆的插入堆的删除 用堆模拟实现优先级队列 常用接口PriorityQueue的特性PriorityQueue常用接口介绍构造方法插入/删除/获取优先级最高的元素 P…

孙溟㠭篆刻,红木上的‘’椎凿稚趣‘’

了解中国传统篆刻的人&#xff0c;一定知道篆刻作品中追求的“金石气”。作为拥有3700多年历史的中国传统艺术&#xff0c;篆刻艺术是将书法&#xff08;主要是篆书&#xff09;和镌刻&#xff08;包括凿、铸&#xff09;相结合&#xff0c;制作印章&#xff0c;亦是汉字独有的…

Vivado 仿真器中以批处理或脚本模式(Batch or Scripted Mode)进行仿真

以下说明来自ug900:在 Vivado 仿真器中以批处理或脚本模式进行仿真 具体可以内容可自行查找 其中代码运行截图为自己实践的实例 Note: xelab, xvlog and xvhdl are not Tcl commands. The xvlog, xvhdl, xelab are Vivado-independent compiler executables. Hence, there is…

20230505使用amazon来批量翻译SRT格式的日语字幕为简体中文

20230505使用amazon来批量翻译SRT格式的日语字幕为简体中文 2023/5/5 19:03 百度搜索&#xff1a;使用 amazon 批量翻译 请严重注意&#xff1a;可能会扣费的&#xff01; https://aws.amazon.com/cn/blogs/china/translating-documents-with-amazon-translate-aws-lambda-and…

线性判别分析LDA计算例题详解

线性判别分析(Linear Discriminant Analysis, LDA)的核心思想是&#xff1a;将给定训练集投影到特征空间的一个超平面上&#xff0c;并设法使同类样本投影点尽可能接近&#xff0c;异类样本投影点尽可能远离 由于做题时针对的是解题过程&#xff0c;因此原理相关方面省略&#…

回文数:探索数字世界中的对称美学

本篇博客我会讲解力扣中的“9. 回文数”这道题&#xff0c;大家重点理解判断回文数的方法。 先来审题&#xff1a;这是题目链接。 来看几个输出示例&#xff1a; 还有一些条件&#xff1a; 第一反应是&#xff1a;为啥是个整数呢&#xff1f;万一是个字符串&#xff0c;那不…

windows下安装OpenCL

由于我的电脑是windows10&#xff0c;显卡是集显Intel UHD Graphics 630。 下载Intel的SDK for OpenCL&#xff0c;下载地址https://software.intel.com/en-us/opencl-sdk/choose-download&#xff0c;也可以在我的资源里面直接下载https://download.csdn.net/download/qq_363…

System verilog【2】字符串,函数,任务

前言 素手青颜光华发&#xff0c;半世尘缘半世沙。我唤青天睁开眼&#xff0c;风霜怎奈并蒂花 \;\\\;\\\; 目录 前言字符串packed组合型结构体组合型数组 过程块initial & always functiontask 字符串 module chertanis;initial beginstring s"hola,mundo!",s2…

Java 多线程知识

参考链接&#xff1a;https://www.cnblogs.com/kingsleylam/p/6014441.html https://blog.csdn.net/ly0724ok/article/details/117030234/ https://blog.csdn.net/jiayibingdong/article/details/124674922 导致Java线程安全问题最主要的原因&#xff1a; &#xff08;1&#…

修改亮度、对比度、色调、饱和度,达到预期效果

用户态可以通过v4l2自带工具进行一些UVC相机参数的设定&#xff0c;包括采集卡驱动之类&#xff0c;也可以通过v4l2自带工具进行参数设定。 通过修改这些参数的值&#xff0c;可以弥补相机本身彩色部分自带不足。 总的来说就这么几种命令&#xff1a; 查看设备所有参数信息&a…

C++系列三:变量、常量

常量、变量 1. 变量1.1 定义变量1.2 初始化变量1.3 变量数据类型1.4 变量作用域 2. 常量2.1 定义常量2.2 常量类型2.3 常量作用域2.4 常量用法 3. 总结 1. 变量 变量是一个用于存储值的命名内存位置&#xff0c;可以存储多种不同类型的数据&#xff0c;例如整数、实数、字符或…

淘宝搜广推技术备注

第一篇文章 一、序列特征处理方式 1&#xff1a;淘宝的类目体系中&#xff0c;有大类目、小类目&#xff08;淘宝大类目和小类目怎么区分&#xff1f;有何运营技巧&#xff1f;-卖家网&#xff09;&#xff0c;在做推荐系统时&#xff0c;有个sim建模&#xff08;search-base…

【Java】抽象类接口

目录 1.抽象类 2.接口 2.1实现多个接口 2.2接口之间的关系 2.3接口使用实例 2.3.1Comparable接口 2.3.2Comparator接口 2.3.2Clone接口 2.4抽象类与接口的区别 1.抽象类 定义&#xff1a;抽象方法&#xff1a;这个方法没有具体的实现&#xff1b; 抽象类&#xff1a;不…