C++ 内存泄漏检测工具——Valgrind(Linux系统)

2024-03-15 03:04

本文主要是介绍C++ 内存泄漏检测工具——Valgrind(Linux系统),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++ 内存泄漏检测工具——Valgrind(Linux系统)

参考来源:valgrind基本功能介绍、基础使用方法说明

文章目录

  • C++ 内存泄漏检测工具——Valgrind(Linux系统)
      • Valgrind
      • 下载和安装
      • Valgrind 使用选项
      • Memcheck工具
      • 例子

Valgrind

Valgrind 是Linux系统下,开放源代码的仿真调试工具的集合。我们可以利用该工具对基于C、C++语言写的项目进行内存泄漏等多个方面进行检测。

下载和安装

https://www.valgrind.org/downloads/

下载好后,到下载目录下,打开终端, 输入以下命令:

# 解压
tar -jxvf valgrind-3.21.0.tar.bz2
# 进入解压目录
cd valgrind-3.21.0
# 执行安装配置命令
./configure --prefix=/usr/local/valgrind-3.21.0
# 编译
make
# 安装
make install
# 建立软链接
ln -s /usr/local/valgrind-3.21.0/bin/valgrind /usr/bin/valgrind

好像也可以用命令安装linux valgrind 安装和使用

sudo apt-get install valgrind

Valgrind 使用选项

(1)Memcheck。这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。
(2)Callgrind。它主要用来检查程序中函数调用过程中出现的问题。
(3)Cachegrind。它主要用来检查程序中缓存使用出现的问题。
(4)Helgrind。它主要用来检查多线程程序中出现的竞争问题。
(5)Massif。它主要用来检查程序中堆栈使用中出现的问题。

1)适用于所有Valgrind工具
–tool=< name > 最常用的选项。运行 valgrind中名为toolname的工具。默认memcheck,还包括cachegrind callgrind helgrind drd massif dhat lackey none exp-bbv
-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

(2)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]

(3)适用于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

对于内存泄漏方面:

valgrind --tool=memcheck --leak-check=full --log-file=log.txt ./main# --tool=memcheck 针对内存检测是固定使用memcheck的
# --leak-check=full 将给出内存泄漏的完整信息
# --leak-check=yes  将给出内存泄漏的信息,但是可能不太好定位
# --leak-check=summary 这个效果跟--leak-check=yes是差不多的
# --log-file=log.txt 则会将内存检测的信息写入到log.txt文件下,log.txt文件在终端当前目录下
# ./main  是linux可执行的程序,这个可执行程序名为main

Memcheck工具

Memcheck主要检测以下错误:

(1) 使用未初始化的内存(Use of uninitialised memory)
(2) 使用已经释放了的内存(Reading/writing memory after it has been free’d)
(3) 使用超过malloc分配的内存空间(Reading/writing off the end of malloc’d blocks)
(4) 对堆栈的非法访问(Reading/writing inappropriate areas on the stack)
(5) 申请的空间是否有释放(Memory leaks – where pointers to malloc’d blocks are lost forever)
(6) malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
(7) src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)

前六种是比较常见的问题,内存泄漏主要是有(4)(5)引起的,由于程序中申请了空间,但是没有在程序结束或是在函数结束时正确的释放,导致这段空间被无法在后面的程序中继续使用。对于数据量较大的程序,这是很危险的,由于内存占用问题,尽管函数或程序可能执行完毕,但是未被释放,但是内存仍被占用,这些空间无法后续使用或被其他程序使用,可能会导致计算机运行变慢,也可能导致后续程序无法正常运行。

例子

本文编译了一个名为PathPlanningFramework的程序,在程序中有一段代码是对矩阵作卷积的,为了测试是否存在内存泄漏的问题,使用如下命令。

valgrind --leak-check=full --log-file=output.txt ./PathPlanngFramework

到当面目录下查看输出log-file。

==51396== Memcheck, a memory error detector
==51396== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==51396== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==51396== Command: ./PathPlanningFramework
==51396== Parent PID: 30810
==51396== 
==51396== 
==51396== HEAP SUMMARY:
==51396==     in use at exit: 40,804 bytes in 1 blocks
==51396==   total heap usage: 1,239 allocs, 1,238 frees, 688,012 bytes allocated
==51396== 
==51396== 40,804 bytes in 1 blocks are definitely lost in loss record 1 of 1
==51396==    at 0x48487EF: malloc (vg_replace_malloc.c:442)
==51396==    by 0x1155C3: void OpMatrix::conv<float>(float*, float*, int, int, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<float, std::allocator<float> >&, int&, int&, bool, bool) (in /home/sunx/WorkSpace/Project/C++Projects/PathPlanningFramework/cmake-build-debug/PathPlanningFramework)
==51396==    by 0x116304: void OpMatrix::Conv<int, int, double>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) (in /home/sunx/WorkSpace/Project/C++Projects/PathPlanningFramework/cmake-build-debug/PathPlanningFramework)
==51396==    by 0x10F7D0: main (in /home/sunx/WorkSpace/Project/C++Projects/PathPlanningFramework/cmake-build-debug/PathPlanningFramework)
==51396== 
==51396== LEAK SUMMARY:
==51396==    definitely lost: 40,804 bytes in 1 blocks
==51396==    indirectly lost: 0 bytes in 0 blocks
==51396==      possibly lost: 0 bytes in 0 blocks
==51396==    still reachable: 0 bytes in 0 blocks
==51396==         suppressed: 0 bytes in 0 blocks
==51396== 
==51396== For lists of detected and suppressed errors, rerun with: -s
==51396== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

可以看到存在40804bytes的内存泄漏。具体的泄漏位置是在OpMatrix::conv<float>(float*, float*, int, int, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<float, std::allocator<float> >&, int&, int&, bool, bool),由这个函数引起的。这个函数被void OpMatrix::Conv<int, int, double>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&),而Convmain调用,最终导致内存泄漏。

那么就去检查conv函数,看看是哪一部分的内存申请了,但是没有释放。

template <typename _Tp>void conv(_Tp* matrix, _Tp* corner, int matrix_w, int matrix_h, int corner_length, std::string conv_type, std::vector<_Tp> & result, int & result_h, int & result_w, bool show, bool is_rot) {result_w = matrix_w - corner_length + 1;result_h = matrix_h - corner_length + 1;// 卷积核逆时针旋转180度if (is_rot) {corner = rot90(corner, corner_length, 2, false);}int conv_key = convtype_str_id.at(conv_type);switch (conv_key){case ID_valid:// 卷积结果的尺寸((matrix_h - corner_length + 1),(matrix_w - corner_length + 1))result_w = matrix_w - corner_length + 1;result_h = matrix_h - corner_length + 1;result.resize(result_w*result_h);// 申请矩阵卷积的运算结果的内存空间
//                result = (_Tp*)malloc(sizeof(_Tp)*result_w*result_h);for (int i = 0; i < result_h; i++) {for (int j = 0; j < result_w; j++) {result[i*result_w + j] = 0;for (int z = 0; z < corner_length; z++) {for (int q = 0; q < corner_length; q++) {result[i*result_w + j] += matrix[(i + z)*matrix_w + j + q] * corner[z*corner_length + q];}}}}break;case ID_full://result = (_Tp*)malloc(sizeof(_Tp)*(matrix_w + corner_length - 1)*(matrix_h + corner_length - 1));// 如果corner的边长为奇数,则用corner的中心点对应matrix的扫描到的点进行卷积运算if (corner_length % 2 == 0) {std::cout << "same型卷积要求卷积核尺寸为奇数" << std::endl;return;}else {// 创建新的matrix_new,用0填充原始matrix_Tp* matrix_new = padMatrix(matrix, matrix_w, matrix_h, matrix_w + 2 * corner_length - 2, matrix_h + 2 * corner_length - 2, false);// 对matrix_new进行full卷积,变相实现same型卷积conv(matrix_new, corner, matrix_w + 2 * corner_length - 2, matrix_h + 2 * corner_length - 2, corner_length, "valid", result, result_h, result_w, show, false);// 释放新申请的空间// free(matrix_new);return;}break;case ID_same://result = (_Tp*)malloc(sizeof(_Tp)*matrix_w*matrix_h);// 如果corner的边长为奇数,则用corner的中心点对应matrix的扫描到的点进行卷积运算if (corner_length % 2 == 0) {std::cout << "same型卷积要求卷积核尺寸为奇数" << std::endl;return;}else {// 创建新的matrix_new,用0填充原始matrix_Tp* matrix_new = padMatrix(matrix, matrix_w, matrix_h, matrix_w + corner_length - 1, matrix_h + corner_length - 1, false);// 对matrix_new进行full卷积,变相实现same型卷积//free(result);conv(matrix_new, corner, matrix_w + corner_length - 1, matrix_h + corner_length - 1, corner_length, "valid", result, result_h, result_w, show, false);// 释放原始matrix// free(matrix_new);return;}break;default:throw "请输入正确的卷积操作类型!";return;}// 打印计算结果
//        if(saveR){
//            Array2Vector<_Tp1, _Tp>(save, result, result_h, result_w);
//        }if (show) {showMatrix(result, result_w, result_h);}}

仔细查看,发现是matrix_new这段空间申请了,但是没有及时释放,所以在后面合适的位置,使用free(matrix_new)释放空间即可。

==51936== Memcheck, a memory error detector
==51936== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==51936== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==51936== Command: ./PathPlanningFramework
==51936== Parent PID: 30810
==51936== 
==51936== 
==51936== HEAP SUMMARY:
==51936==     in use at exit: 0 bytes in 0 blocks
==51936==   total heap usage: 1,239 allocs, 1,239 frees, 688,012 bytes allocated
==51936== 
==51936== All heap blocks were freed -- no leaks are possible
==51936== 
==51936== For lists of detected and suppressed errors, rerun with: -s
==51936== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

修改后再次进行检测,可以看到没有内存泄漏问题。

这篇关于C++ 内存泄漏检测工具——Valgrind(Linux系统)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/810580

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�