内存

Valgrind 排查内存泄漏实战

Valgrind 是 Linux 下最强大的内存调试工具,无需修改代码即可检测内存泄漏、越界访问和未初始化读取。本文通过 4 个典型场景演示定位流程。

一、安装与基本用法

sudo apt install valgrind
valgrind --leak-check=full ./your_program

常用参数组合:

  • --leak-check=full — 显示每个泄漏块的详细调用栈
  • --show-leak-kinds=all — 显示 definitely/indirectly/possibly/reachable 所有类型
  • --track-origins=yes — 追踪未初始化值的来源

二、场景 1: definitely lost(确定泄漏)

分配了内存但没有任何指针指向它,这是最常见的泄漏类型。

void leak1(void) {
    int *p = malloc(sizeof(int) * 10);
    p = NULL;  /* 原内存丢失,无法 free */
}

Valgrind 报告:

==1234== 40 bytes in 1 blocks are definitely lost
==1234==    at 0x4C2E80F: malloc (vg_replace_malloc.c:...)
==1234==    by 0x4005E6: leak1 (main.c:5)
==1234==    by 0x40060A: main (main.c:12)

三、场景 2:invalid write(越界写入)

void overflow(void) {
    int *p = malloc(sizeof(int) * 5);
    p[5] = 100;  /* 越界!有效下标 0~4 */
    free(p);
}

Valgrind 会报告 Invalid write of size 4,并指出实际分配了 20 字节,但写入了偏移 20 的位置。

四、场景 3:use after free(释放后使用)

void uaf(void) {
    int *p = malloc(sizeof(int));
    *p = 42;
    free(p);
    printf("%d\n", *p);  /* 使用已释放内存 */
}

五、场景 4:double free(重复释放)

void double_free(void) {
    int *p = malloc(sizeof(int));
    free(p);
    free(p);  /* 重复释放,可能导致崩溃 */
}

六、Suppressions 规则

对于第三方库的已知"假泄漏",可以编写 suppressions 文件过滤:

{
   known_lib_leak
   Memcheck:Leak
   match-leak-kinds: reachable
   ...
}
使用 valgrind --gen-suppressions=yes 自动生成 suppression 规则,保存到 .supp 文件后通过 --suppressions=file.supp 加载。