Valgrind调试内存泄漏

2024-04-19 19:36
文章标签 内存 调试 泄漏 valgrind

本文主要是介绍Valgrind调试内存泄漏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、简介

二、下载安装

 三、主要工具

四、Valgrind使用

五、总结分享


一、简介

        当你在写程序时,内存错误是常见的问题之一。有时候为了解决这种问题,你可能会耗费大量的时间和精力。今天我向大家推荐一款深得大家喜欢的工具---Valgrind,它是一个强大的工具,用于内存调试、内存泄漏检测以及性能分析,可以帮助你找到和修复这些问题,提高程序的稳定性和性能。

二、下载安装

下载地址:Valgrind: Current Releasesicon-default.png?t=N7T8https://valgrind.org/downloads/

1、下载安装包

wget https://sourceware.org/pub/valgrind/valgrind-3.22.0.tar.bz2

2、解压缩

tar -xjf valgrind-3.22.0.tar.bz2

 3、进入到该目录下

cd valgrind-3.22.0 

4、配置生成路径

./configure --prefix=`pwd`/../install

        使用./configure --help 可以查看配置项。

5、利用makefile进行安装

makemake install

        安装时间有点长,耐心等待一下......

 三、主要工具

        Valgrind提供了一些基本工具,用于不同类型的调试和性能分析。

Memcheck最常用的工具之一,用于检测内存错误。它可以检测到内存泄漏、未初始化的内存读取、使用已释放内存、使用无效指针等问题。Memcheck会在程序运行时对内存进行监视,并在发现问题时报告。
Cachegrind用于缓存分析(分析CPU的cache命中率、丢失率),可以帮助你了解程序的缓存访问模式,从而优化程序的性能。
Callgrind用于函数调用分析,检查程序中函数调用过程中出现的问题。
Helgrind检测多线程程序中的竞争条件和死锁。它可以帮助你发现并修复多线程程序中的同步问题。

        接下来,向大家主要介绍Memcheck工具:

        Memcheck通过在程序运行时进行内存访问的监视和跟踪来工作。它会在内存中分配一个影子(shadow)内存,用于跟踪程序中的每个字节的状态。具体来说,它会记录每个字节是否被初始化、是否被分配、是否被释放等信息。

        当程序访问内存时,Memcheck会检查相应内存字节的状态,如果发现不符合规则的访问(比如读取未初始化的内存、访问已释放的内存等),就会报告错误。

Memcheck检测的主要问题:

1.非法读写错误 :

        比如读写还没有分配的内存块、读写已经被free的内存块、内存访问越界。提示信息:[invalid read of size 4]

2.使用未初始化的内存/使用了未定义的值:

        函数中的局部变量没有被初始化;堆上的内存块在使用之前没有被初始化。提示信息:[Conditional jump or move depends on uninitialised value]

3.系统调用中参数未已经初始化,程序提供的buffer不可用:

        提示信息:[syscall param write(buf) points to uninitilaised bytes]

4.非法释放:

        重复释放内存块,或者指针没有指向内存的起始位置。提示信息:[invalid free()]

5.使用不适当的释放函数释放:

  • 如果与分配 malloc, calloc, realloc, valloc或者 memalign,必须使用free。

  • 如果分配new,必须使用delete。

  • 如果分配new[],必须使用delete[]。

        提示信息:[Mismatched free()/delete/delete[]]

6.内存块重叠:

        比如使用 memcpy 函数时源地址和目标地址发生重叠。提示信息:[source and destination overlap in memcpy(,)]

7.Fishy argument values:

        需要的内存大小是负数或者大的离谱的正数。提示信息:[Argument ‘size’ of function malloc has a fishy (possibly negative) value: -3]

8.内存泄漏:

  • still reachable:内存指针还在还有机会使用或释放,指针指向的动态内存还没有被释放就退出了

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

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

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

四、Valgrind使用

一共两步:

1、编译

gcc test.c -g -o test

2、使用Memcheck进行检测

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

-tool=<name> 最常用的选项。运行 valgrind中名为toolname的工具。默认memcheck。
-log-file=<file> 将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID

-leak-check=no|summary|full 要求对leak给出详细信息? [summary]

         接下来,叫我们用几个代码来实际操作一下吧!

(1)使用未初始化的内存(野指针)

#include <stdio.h>int main()
{char    *p; char    c = *p; printf("%c\n",c);return 0;
}

 (2)在内存被释放后进行读/写(使用野指针)

#include <stdio.h>
#include <stdlib.h>int main()
{int *p = (int *)malloc(sizeof(int));*p = 100;free(p);int a = *p; return 0;
}

(3)内存泄漏

#include <stdio.h>
#include <stdlib.h>int main()
{int *p = (int *)malloc(sizeof(int)*100);*p = 100;return 0;
}

堆内存泄露报告

  • 堆内存使用情况概述(HEAP SUMMARY)

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

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

  • 泄露情况概述(LEAK SUMMARY)

五、总结分享

        当你在写程序时,你可能会感觉到疑惑,明明我的程序没有调用malloc,为什么Valgrind显示我多次调用malloc引起内存泄漏?

        这可能是因为你的代码中使用了依赖库或框架,在其内部可能使用了malloc或类似的动态内存分配函数。Valgrind 会跟踪整个程序的内存分配和释放情况,因此它会显示出这些依赖库或框架中的动态内存分配情况,即使你的代码本身没有直接使用malloc等函数。

    接下来和大家分享一下我在程序中遇见的内存泄漏问题。    

1、sqlite3_get_table()函数

该函数原型如下:

int sqlite3_get_table(sqlite3 *db,              /* Database handle */const char *Sql,         /* SQL query to be executed */char ***Result,        /* Pointer to array of result rows */int *nRow,               /* Number of result rows written here */int *nColumn,            /* Number of result columns written here */char **Errmsg           /* Error msg written here */
);

        这个函数的工作原理是执行 SQL 查询并将结果存储在一个二维字符数组中,然后返回指向这个数组的指针。因此,它在内部会使用malloc来分配足够的内存来容纳查询结果。

        由于sqlite3_get_table使用了malloc,所以在使用完查询结果后,必须调用sqlite3_free_table 来释放由sqlite3_get_table 分配的内存,以避免内存泄漏问题。这个函数会释放整个结果数组及其内部的字符串数组所分配的内存。

        除此之外,如果在调用 sqlite3_get_table函数时出现了错误(比如语法错误、查询失败等),则 Errmsg指向的内存将被写入错误信息。在处理完错误后,调用者需要调用sqlite3_free释放Errmsg 指向的内存,以避免内存泄漏。

2、getaddrinfo()函数

该函数原型如下:

int getaddrinfo(const char *node, const char *service,const struct addrinfo *hints, struct addrinfo **res);

        函数是用于执行主机名到 IP 地址以及服务名到端口号的转换的函数,它在 C 语言的网络编程中非常常用。该函数在内部可能会调用malloc函数,用于动态分配内存来存储返回的结果结构体链表。

        具体来说,getaddrinfo 函数会返回一个 addrinfo 结构体链表,每个节点表示一个可能的主机名和服务名对应的 IP 地址和端口号。这些 addrinfo 结构体的内存是在 getaddrinfo 函数内部使用 malloc 动态分配的。因此,在使用 getaddrinfo 函数时,需要注意在使用完返回的结果后,调用 freeaddrinfo 函数来释放动态分配的内存,避免内存泄漏。

        目前就遇到这么多问题,欢迎大家补充,如果后续遇到更多问题,我会再进行详细补充!

这篇关于Valgrind调试内存泄漏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

最新Spring Security的基于内存用户认证方式

《最新SpringSecurity的基于内存用户认证方式》本文讲解SpringSecurity内存认证配置,适用于开发、测试等场景,通过代码创建用户及权限管理,支持密码加密,虽简单但不持久化,生产环... 目录1. 前言2. 因何选择内存认证?3. 基础配置实战❶ 创建Spring Security配置文件

java内存泄漏排查过程及解决

《java内存泄漏排查过程及解决》公司某服务内存持续增长,疑似内存泄漏,未触发OOM,排查方法包括检查JVM配置、分析GC执行状态、导出堆内存快照并用IDEAProfiler工具定位大对象及代码... 目录内存泄漏内存问题排查1.查看JVM内存配置2.分析gc是否正常执行3.导出 dump 各种工具分析4.

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.