当前位置: 首页 > news >正文

利用 Valgrind 检测 C++ 内存泄露

Valgrind 是一款运行在 Linux 系统上的编程工具集,主要用于调试和分析程序的性能、内存使用等问题。其中最常用的工具是 Memcheck,它可以帮助检测 C 和 C++ 程序中的内存管理错误,如内存泄漏、使用未初始化的内存、越界访问等。

安装

这里我以Ubuntu 22.04(WSL)为例子,安装很简单:

sudo apt-get install valgrind
bluebonnet27@bluebonnet27:~/Project/CPP$ valgrind --version
valgrind-3.18.1

使用

编写包含潜在内存泄露问题的 C++ 代码

以下是一个简单的 C++ 程序示例,其中存在内存泄露问题

#include <iostream>int main() {int* ptr = new int[10];// 没有释放分配的内存return 0;
}

在这个程序中,我们使用new操作符分配了一个包含 10 个整数的数组,但没有使用delete[]来释放这块内存,从而导致了内存泄露。

编译程序

使用g++编译器编译程序,并确保开启调试信息(使用-g选项),这样 Valgrind 在检测到问题时可以提供更详细的错误信息:

g++ -g -o memLeak memLeak.cpp

使用 Valgrind 运行程序

使用 Valgrind 的 Memcheck 工具来运行编译好的程序:

valgrind --leak-check=full --show-leak-kinds=all ./memLeak

分析 Valgrind 的输出结果

运行上述命令后,Valgrind 会输出详细的内存使用信息和检测到的问题

==36044== Memcheck, a memory error detector
==36044== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==36044== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==36044== Command: ./memLeak
==36044== 
==36044== 
==36044== HEAP SUMMARY:
==36044==     in use at exit: 40 bytes in 1 blocks
==36044==   total heap usage: 2 allocs, 1 frees, 72,744 bytes allocated
==36044== 
==36044== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==36044==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==36044==    by 0x10919E: main (memLeak.cpp:4)
==36044== 
==36044== LEAK SUMMARY:
==36044==    definitely lost: 40 bytes in 1 blocks
==36044==    indirectly lost: 0 bytes in 0 blocks
==36044==      possibly lost: 0 bytes in 0 blocks
==36044==    still reachable: 0 bytes in 0 blocks
==36044==         suppressed: 0 bytes in 0 blocks
==36044== 
==36044== For lists of detected and suppressed errors, rerun with: -s
==36044== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

从输出中可以看到,definitely lost: 40 bytes in 1 blocks 表示确定存在 40 字节的内存泄露,并且指出泄露发生在 memLeak.cpp 文件的第 4 行,这正是我们使用new分配内存但没有释放的地方。

修复内存泄露问题

根据 Valgrind 的输出信息,修改代码来释放分配的内存:

#include <iostream>int main() {int* ptr = new int[10];// 释放分配的内存delete[] ptr;return 0;
}

重新编译并使用 Valgrind 运行修改后的程序

==36689== Memcheck, a memory error detector
==36689== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==36689== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==36689== Command: ./memLeak
==36689== 
==36689== 
==36689== HEAP SUMMARY:
==36689==     in use at exit: 0 bytes in 0 blocks
==36689==   total heap usage: 2 allocs, 2 frees, 72,744 bytes allocated
==36689== 
==36689== All heap blocks were freed -- no leaks are possible
==36689== 
==36689== For lists of detected and suppressed errors, rerun with: -s
==36689== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

此时不再有内存泄漏。

valgrind的局限性

下面的代码也存在内存泄漏,因为使用基类指针指向派生类对象,并且基类的析构函数不是虚函数时,通过基类指针删除对象可能不会调用派生类的析构函数,从而导致派生类部分的内存没有被正确释放。

#include <iostream>class Base {
public:Base() { std::cout << "Base constructor" << std::endl; }~Base() { std::cout << "Base destructor" << std::endl; }
};class Derived : public Base {
public:Derived() { std::cout << "Derived constructor" << std::endl; }~Derived() { std::cout << "Derived destructor" << std::endl; }
};void memoryLeak4() {Base* ptr = new Derived();delete ptr; // 只会调用基类的析构函数,派生类部分内存未释放
}int main() {memoryLeak4();return 0;
}

但这样的代码并不能被valgrind检测出内存泄漏,因为 Valgrind 主要基于内存分配和释放操作来判断是否有泄漏,而这种情况下内存的释放操作确实执行了(基类部分的内存被释放),只是派生类部分的析构函数没有被调用,没有从表面上体现出 “未释放” 的特征。

我们修改下代码,让Derived 类的构造函数里使用 new[] 分配了一个包含 10 个 int 元素的数组,而析构函数中使用 delete[] 来释放这块内存。当使用基类指针 Base* ptr = new Derived(); 创建派生类对象,并且基类析构函数不是虚函数时,执行 delete ptr; 只会调用基类的析构函数,派生类的析构函数不会被调用,这就导致 data 所指向的内存没有被释放。

#include <iostream>class Base {
public:Base() { std::cout << "Base constructor" << std::endl; }~Base() { std::cout << "Base destructor" << std::endl; }
};class Derived : public Base {
private:int* data;
public:Derived() {std::cout << "Derived constructor" << std::endl;data = new int[10]; // 派生类中动态分配内存}~Derived() {std::cout << "Derived destructor" << std::endl;delete[] data; // 释放派生类中分配的内存}
};void memoryLeak4() {Base* ptr = new Derived();delete ptr; // 只会调用基类的析构函数,派生类部分内存未释放
}int main() {memoryLeak4();return 0;
}

此时 Valgrind 就能检测到内存泄漏了,并正确打印了内存泄漏的代码行:

==37900== Memcheck, a memory error detector
==37900== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==37900== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==37900== Command: ./memLeak
==37900== 
Base constructor
Derived constructor
Base destructor
==37900== 
==37900== HEAP SUMMARY:
==37900==     in use at exit: 40 bytes in 1 blocks
==37900==   total heap usage: 4 allocs, 3 frees, 73,776 bytes allocated
==37900== 
==37900== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==37900==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==37900==    by 0x1093EB: Derived::Derived() (memLeak.cpp:15)
==37900==    by 0x10924C: memoryLeak4() (memLeak.cpp:24)
==37900==    by 0x1092A6: main (memLeak.cpp:29)
==37900== 
==37900== LEAK SUMMARY:
==37900==    definitely lost: 40 bytes in 1 blocks
==37900==    indirectly lost: 0 bytes in 0 blocks
==37900==      possibly lost: 0 bytes in 0 blocks
==37900==    still reachable: 0 bytes in 0 blocks
==37900==         suppressed: 0 bytes in 0 blocks
==37900== 
==37900== For lists of detected and suppressed errors, rerun with: -s
==37900== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

相关文章:

利用 Valgrind 检测 C++ 内存泄露

Valgrind 是一款运行在 Linux 系统上的编程工具集&#xff0c;主要用于调试和分析程序的性能、内存使用等问题。其中最常用的工具是 Memcheck&#xff0c;它可以帮助检测 C 和 C 程序中的内存管理错误&#xff0c;如内存泄漏、使用未初始化的内存、越界访问等。 安装 这里我以…...

Python中的HTTP客户端库:httpx与request | python小知识

Python中的HTTP客户端库&#xff1a;httpx与request | python小知识 在Python中&#xff0c;发送HTTP请求和处理响应是网络编程的基础。requests和httpx是两个常用的HTTP库&#xff0c;它们都提供了简洁易用的API来发送HTTP请求。然而&#xff0c;httpx作为新一代的HTTP客户端…...

【Python】Python入门基础——环境搭建

学习Python&#xff0c;首先需要搭建一个本地开发环境&#xff0c;或是使用线上开发环境&#xff08;各类练习网站&#xff09;&#xff0c;这里主要记录本地开发环境的配置。 目录&#xff1a; 一、下载和安装python解释器 官网下载地址&#xff1a;Download Python | Pytho…...

2025 pwn_A_childs_dream

文章目录 fc/sfc mesen下载和使用推荐 fc/sfc https://www.mesen.ca/docs/ mesen2安装&#xff0c;vscode安装zg 任天堂yyds w d 左右移动 u结束游戏 i崩溃或者卡死了 L暂停 D658地方有个flag 发现DEEE会使用他。且只有这个地方&#xff0c;maybe会输出flag&#xff0c;应…...

面试题整理:操作系统

文章目录 操作系统操作系统基础1. 操作系统的功能&#xff1f;2. 什么是用户态和内核态&#xff1f; 进程和线程1. 是什么&#xff1f;区别&#xff1f;2. ⭐线程间的同步的方式有哪些&#xff1f;3. PCB 是什么&#xff1f;包含哪些信息&#xff1f;4. 进程的状态有哪些&#…...

构建未来教育的基石:智慧校园与信息的重要性

随着科技的迅猛发展&#xff0c;教育领域正经历一场深刻的变革。在这个过程中&#xff0c;“智慧校园”作为教育信息化的重要实践&#xff0c;扮演着不可或缺的角色。智慧校园不仅仅是硬件设施的升级&#xff0c;更是一种全新的教育理念&#xff0c;强调利用信息技术优化教育资…...

C# 控制台相关 API 与随机数API

C# 控制台相关 API 与随机数API 控制台输入输出 功能说明 Console.WriteLine(string): 输出字符串并换行Console.Write(string, string): 输出字符串不换行Console.ReadLine(): 等待用户输入并返回字符串Console.ReadKey(bool).KeyChar: 读取按键&#xff0c;指定是否显示输…...

【踩坑】⭐️MyBatis的Mapper接口中不建议使用重载方法

目录 &#x1f378;前言 &#x1f37b;一、背景 &#x1f379;二、问题处理 &#x1f49e;️三、处理方法 &#x1f378;前言 小伙伴们大家好&#xff0c;很久没有水..不是&#xff0c;写文章了&#xff0c;都收到系统的消息了&#xff1b;我算下时间&#xff0c;上周是单休…...

CSS Grid 网格布局,以及 Flexbox 弹性盒布局模型,它们的适用场景是什么?

CSS Grid网格布局和Flexbox弹性盒布局模型都是现代CSS布局的重要工具&#xff0c;它们各自具有独特的优势和适用场景。 作为前端开发工程师&#xff0c;理解这些布局模型的差异和适用场景对于编写高效、可维护的代码至关重要。 CSS Grid网格布局 适用场景&#xff1a; 复杂…...

HDFS体系结构

HDFS 支持主从结 构 &#xff0c; 主节 点 称为 NameNode &#xff0c;从节点称为 DataNode HDFS中还包含一个 SecondaryNameNode 进程&#xff0c;只要辅助主节点 公司BOSS&#xff1a;NameNode &#xff08;NN&#xff09; 秘书&#xff1a;SecondaryNameNode (2NN) 员工&a…...

AI大模型的技术突破与传媒行业变革

性能与成本&#xff1a;AI大模型的“双轮驱动” 过去几年&#xff0c;AI大模型的发展经历了从实验室到产业化的关键转折。2025年初&#xff0c;以DeepSeek R1为代表的模型在数学推理、代码生成等任务中表现超越国际头部产品&#xff0c;而训练成本仅为传统模型的几十分之一。这…...

vscode/cursor+godot C#中使用socketIO

在 Visual Studio Code(VS Code)中安装 NuGet 包&#xff08;例如SocketIOClient&#xff09;&#xff0c;你可以通过以下几种方法&#xff1a; 方法 1&#xff1a;使用dotnet cli 打开终端&#xff1a;在 VS Code 中按下Ctrl 或者通过菜单View -> Terminal打开终端。 导…...

分段线性插值

分段线性插值 分段线性插值&#xff0c;就是将插值点用折线段连接起来逼近f(x)。设已知节点 a x 0 < x 1 < ⋅ ⋅ ⋅ < x n b ax_0<x_1<<x_nb ax0​<x1​<⋅⋅⋅<xn​b上的函数值 f 0 , f 1 , . . . , f n f_0,f_1,...,f_n f0​,f1​,...,fn​&a…...

制作一个项目用于研究elementUI的源码

需求&#xff1a;修改el-tooltip的颜色&#xff0c;发现传递参数等方法都不太好用&#xff0c;也可以使用打断点的方式&#xff0c;但也有点麻烦&#xff0c;因此打算直接修改源码&#xff0c;把组件逻辑给修改了 第一步下载源码 源码地址 GitHub - ElemeFE/element: A Vue.j…...

[AI]从零开始的llama.cpp部署与DeepSeek格式转换、量化、运行教程

一、前言 在上一次的DeepSeek的部署教程中&#xff0c;我们使用Ollama与LM Studio很轻松的部署了DeepSeek并且也完成了相关API的调用&#xff0c;如果还有不会的小伙伴请看下面的教程&#xff1a; DeepSeek本地部署&#xff1a;[AI]从零开始的DeepSeek本地部署及本地API调用教…...

vLLM专题(二):安装-CPU

vLLM 是一个 Python 库,支持以下 CPU 变体。选择您的 CPU 类型以查看供应商特定的说明: Intel/AMD x86 vLLM 最初支持在 x86 CPU 平台上进行基本模型推理和服务,支持的数据类型包括 FP32、FP16 和 BF16。 注意 此设备没有预构建的 wheel 包或镜像,因此您必须从源代码构建 v…...

JVM 底层探秘:对象创建的详细流程、内存分配机制解析以及线程安全保障策略

文章目录 1. 类加载检查2. 内存分配① 指针碰撞② 空闲列表线程安全问题&#xff1a; 3. 内存空间初始化4. 对象头设置5. 对象初始化 当Java虚拟机遇到一条 new指令时&#xff0c;会执行以下步骤来创建对象&#xff1a; 1. 类加载检查 首先检查new指令的参数是否能在常量池中…...

【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter14-DOM

十四、DOM 文档对象模型&#xff08;DOM&#xff0c;Document Object Model&#xff09;是 HTML 和 XML 文档的编程接口。DOM 表示由多层节点构成的文档&#xff0c;通过它开发者可以添加、删除和修改页面的各个部分。脱胎于网景和微软早期的动态 HTML&#xff08;DHTML&#x…...

外汇掉期(FX Swap):全球企业管理外汇风险的关键工具(中英双语)

外汇掉期&#xff08;FX Swap&#xff09;&#xff1a;全球企业管理外汇风险的关键工具 引言 在全球化经济环境下&#xff0c;跨国公司、银行和金融机构经常面临外汇风险&#xff0c;因为它们的业务涉及多种货币。例如&#xff0c;一家中国公司可能需要欧元支付欧洲供应商&am…...

verilog程序设计及SystemVerilog验证

1.Verilog测试程序设计基础 1.1Testbench及其结构 在仿真的时候Testbench用来产生测试激励给待验证设计( Design Under Verification, DUV)&#xff0c;或者称为待测设计(Design UnderTest, DUT) 。 测试程序的一般结构&#xff1a; Testbench是一个测试平台&#xff0c;信号…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...