Memory Leak和Valgrind

首先必须搞懂什么才是Memory Leak?其实业界一直有两种定义。

a. 大众化说法:一块内存由new或者malloc分配了,在程序结束前一直没有被回收。但程序始终有指针指向这块内存。

b. 更严格的说法:一块内存由new或者malloc分配在堆上面,在程序结束前,已经没有任何指针能够指向这块内存了。

对于第一种Memory Leak,其实危害不大,因为一旦进程结束了,所有该进程分配的内存(包括Leak掉的内存)都会被kernel回收。对于第二种Memory Leak,大家一致认为对大型服务器端运行的程序是有危害的。如果程序一直在执行,Leak的内存会越来越多,可能会耗尽程序的堆内存。

相应的,在Valgrind里面,称第一种Leak为“still reachable”,称第二种为“memory leak”。对于memory leak又分为两种。Directly lost和Indirectly lost。

image

上图中的BBB在case (1),(2)情况下是Still reachable。Case (3)是Directly lost,而Case(4)是Indirectly lost。用一个例子能够很清楚的说明问题。

#include 
#include <string.h>

void **rrr;
int main(void)
{
    /* Allocation of AAA block, start-pointer in RRR */
    rrr = malloc(sizeof(void *));

    /* Allocation of BBB block, start-pointer in AAA */
    *rrr = strdup("bbb");

    /* oops, we lost the start-pointer to AAA */
    rrr = NULL;
    return 0;
}
用Valgrind检查上面的代码:
$ valgrind --leak-check=full --show-reachable=yes ./a.out

==16420== 4 bytes in 1 blocks are indirectly lost in loss record 1 of 2

==16420== at 0x4A05E1C: malloc (vg_replace_malloc.c:195)

==16420== by 0x374EA79771: strdup (in /lib64/libc-2.5.so)

==16420== by 0x4005E2: main (in /home/zzhan17/test/a.out)

==16420==

==16420== 12 (8 direct, 4 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2

==16420== at 0x4A05E1C: malloc (vg_replace_malloc.c:195)

==16420== by 0x4005CA: main (in /home/zzhan17/test/a.out)

==16420==

==16420== LEAK SUMMARY:

==16420== definitely lost: 8 bytes in 1 blocks

==16420== indirectly lost: 4 bytes in 1 blocks

==16420== possibly lost: 0 bytes in 0 blocks

==16420== still reachable: 0 bytes in 0 blocks

==16420== suppressed: 0 bytes in 0 blocks

如果把上面的“rrr = NULL; ”代码删除, Valgrind不会报告任何memory leak但会显示有memory still reachable,原因是void **rrr是global pointer,程序退出时rrr还能指向AAA和BBB。

image

因此,最为重要的是分析Definitely lost和Indirectly lost,也就是以上的Case 3, 4和9。所谓的Interior lost是指向block内的指针,也就是我们常说的野指针。所以很多Possible lost并不是真正的Memory leak。

以后有空的话还会给大家介绍Valgrind的其他模块,如Callgrind,CacheGrind,还有图形化的工具KCacheGrind。这些对Performance Tuning都很有帮助。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GDB和Valgrind都是常用的调试工具,可以帮助开发人员找到程序中的错误。下面是它们的简单介绍以及如何使用它们进行调试的步骤: ## GDB GDB是GNU调试器,可以用来调试C和C++程序。下面是使用GDB进行调试的步骤: 1. 在编译时,需要在命令行加上-g选项,以生成调试信息。例如: ``` gcc -g -o program program.c ``` 2. 启动GDB,命令为: ``` gdb program ``` 3. 在GDB中运行程序,命令为: ``` (gdb) run ``` 4. 如果程序崩溃或停止了,可以使用backtrace命令查看函数调用栈: ``` (gdb) backtrace ``` 5. 使用print命令查看变量的值: ``` (gdb) print variable_name ``` 6. 使用break命令设置断点: ``` (gdb) break line_number ``` 7. 使用step命令单步执行代码: ``` (gdb) step ``` ## Valgrind Valgrind是一个内存调试和性能分析工具,可以检测内存泄漏、越界访问等问题。下面是使用Valgrind进行调试的步骤: 1. 在编译时,需要在命令行加上-g选项,以生成调试信息。例如: ``` gcc -g -o program program.c ``` 2. 启动Valgrind,命令为: ``` valgrind --tool=memcheck --leak-check=yes ./program ``` 3. Valgrind会在程序执行完成后输出内存错误信息。 ``` ==1234== Memcheck, a memory error detector ==1234== Copyright (C) ... ==1234== ... ==1234== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ==1234== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ``` 4. 如果有内存错误,Valgrind会输出详细的信息,包括错误堆栈和错误位置等。例如: ``` ==1234== Invalid read of size 4 ==1234== at 0x8048400: main (program.c:10) ==1234== Address 0x0 is not stack'd, malloc'd or (recently) free'd ==1234== ==1234== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) ==1234== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) ``` 可以看到,GDB和Valgrind都是非常有用的调试工具,可以帮助开发人员快速找到程序中的错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值