Valgrind查找内存泄漏和句柄泄漏问题

背景:

项目中遇到wifi偶发性打开失败的问题,但是可以确定的是驱动层是没有问题的,那么肯定就是中间层哪里出问题了,后面通过日志排查,大概能确定的是哪里存在句柄泄露了,导致wifi在调用socket的时候,由于句柄池已满,打开失败了,但是具体是哪里有句柄泄露,不好排查,最后还是在网上查到可以借助Valgrind,于是在加上调试信息后,敲valgrind --tool=memcheck --track-fds=yes ./your_program,最终定位到了问题。

Valgrind 基础介绍

Valgrind 是一款用于内存调试、内存泄漏检测及性能分析的工具集。其中 memcheck 是默认工具,用于检测内存泄漏和非法内存访问。

安装 Valgrind

在 Linux 系统中,可以通过包管理器安装:

sudo apt-get install valgrind  # Debian/Ubuntu
sudo yum install valgrind      # CentOS/RHEL

注意:嵌入式项目中,可以先make menuconfig看下系统有没有集成valgrind,如果有的话,需要选中,不然无法直接使用这个工具;如果没有集成这个工具,那就需要自己去打包源码,用项目工具链编译,然后下载到机器中了。

基本内存泄漏检测

以下是一个简单的 C 程序示例,包含内存泄漏问题:

// demo_leak.c
#include <stdlib.h>

void leak() {
    malloc(10);  // 未释放的内存
}

int main() {
    leak();
    return 0;
}

 

使用 Valgrind 检测内存泄漏:

gcc -g demo_leak.c -o demo_leak
valgrind --leak-check=full ./demo_leak

 

Valgrind 输出解析

Valgrind 的输出会显示以下关键信息:

  • Definitely lost:明确的内存泄漏。
  • Indirectly lost:间接内存泄漏(如结构体中指针未释放)。
  • Possibly lost:可能的内存泄漏(指针指向内存中间位置)。
  • Still reachable:程序结束时仍可访问的内存(通常为全局变量)。

检测句柄泄漏

句柄泄漏(如文件描述符未关闭)可以通过 valgrind 结合 --track-fds=yes 选项检测:

// demo_fd_leak.c
#include <fcntl.h>
#include <unistd.h>

void fd_leak() {
    open("temp.txt", O_CREAT | O_RDWR, 0644);  // 未关闭的文件描述符
}

int main() {
    fd_leak();
    return 0;
}

 

运行命令:

gcc -g demo_fd_leak.c -o demo_fd_leak
valgrind --track-fds=yes ./demo_fd_leak

 

检测系统库函数的内存泄漏

Valgrind 可以检测应用程序调用的系统库函数(如 glibc)中的内存泄漏。以下是一个调用 strdup 的示例:

// demo_lib_leak.c
#include <string.h>
#include <stdlib.h>

void lib_leak() {
    char *s = strdup("hello");  // 未释放的内存
}

int main() {
    lib_leak();
    return 0;
}

 

运行命令:

gcc -g demo_lib_leak.c -o demo_lib_leak
valgrind --leak-check=full ./demo_lib_leak

 

Valgrind 常用命令选项

  1. 基本内存检查

    valgrind --leak-check=full ./your_program
    

     

  2. 显示所有内存错误

    valgrind --tool=memcheck --show-reachable=yes ./your_program
    

     

  3. 跟踪文件描述符

    valgrind --track-fds=yes ./your_program
    

     

  4. 生成详细日志文件

    valgrind --log-file=valgrind.log --leak-check=full ./your_program
    

     

  5. 忽略特定错误(如已知的库函数问题):

    valgrind --suppressions=suppress.txt ./your_program
    

     

高级用法:抑制误报

某些系统库可能会触发误报。可以通过编写抑制文件忽略这些错误。例如:

# suppress.txt
{
   <glibc_2.30_strdup>
   Memcheck:Leak
   fun:strdup
}

 

运行命令:

valgrind --suppressions=suppress.txt --leak-check=full ./your_program

 

实际案例:检测多线程内存泄漏

以下是一个多线程内存泄漏的示例:

// demo_thread_leak.c
#include <pthread.h>
#include <stdlib.h>

void *thread_func(void *arg) {
    malloc(20);  // 线程中未释放的内存
    return NULL;
}

int main() {
    pthread_t tid;
    pthread_create(&tid, NULL, thread_func, NULL);
    pthread_join(tid, NULL);
    return 0;
}

 

运行命令:

gcc -g demo_thread_leak.c -o demo_thread_leak -lpthread
valgrind --leak-check=full ./demo_thread_leak

 

注意事项

  1. 编译时务必加上 -g 选项以生成调试信息。
  2. Valgrind 会显著降低程序运行速度,仅用于调试环境。
  3. 对于大型项目,建议结合 --log-file 将输出重定向到文件。

通过以上方法和示例,可以高效地使用 Valgrind 检测内存泄漏、句柄泄漏以及系统库函数的内存问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值