内存检测工具--Valgrind

编译要求

编译时必须带 -g
-g 代表 Debug(调试)。它告诉编译器在编译汇编代码的同时,把源代码的额外信息(如变量名、函数名、数据类型和代码行号)以特定格式(如 DWARF 格式)写入到最终的可执行文件中。
常用编译格式:gcc -g -O0 -fno-omit-frame-pointer -Wall -Wextra -o app main.c foo.c
-g    //添加调试信息
-O0   //优化级别 不优化
-Wall -Wextra:先用编译器把明显问题扫一遍(能省大量时间)
-fno-omit-frame-pointer(让栈回溯更稳定 --帧)

基础使用 

valgrind ./a.out

内存泄漏代码例:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 int main() {
  5     int *p = malloc(sizeof(int) * 10);
  6     printf("%d\n", p[5]);  // 未初始化读                                    
  7     return 0;              // 泄漏:没 free
  8 }

错误报告:

==5562== Memcheck, a memory error detector
==5562== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5562== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5562== Command: ./a.out
==5562== 
==5562== Conditional jump or move depends on uninitialised value(s)
==5562==    at 0x4E9A8AA: vfprintf (vfprintf.c:1642)
==5562==    by 0x4EA2EE5: printf (printf.c:33)
==5562==    by 0x1086BC: main (test.c:6)
==5562== 
==5562== Use of uninitialised value of size 8
==5562==    at 0x4E9683B: _itoa_word (_itoa.c:179)
==5562==    by 0x4E99EDD: vfprintf (vfprintf.c:1642)
==5562==    by 0x4EA2EE5: printf (printf.c:33)
==5562==    by 0x1086BC: main (test.c:6)
==5562== 
==5562== Conditional jump or move depends on uninitialised value(s)
==5562==    at 0x4E96845: _itoa_word (_itoa.c:179)
==5562==    by 0x4E99EDD: vfprintf (vfprintf.c:1642)
==5562==    by 0x4EA2EE5: printf (printf.c:33)
==5562==    by 0x1086BC: main (test.c:6)
==5562== 
==5562== Conditional jump or move depends on uninitialised value(s)
==5562==    at 0x4E99FE4: vfprintf (vfprintf.c:1642)
==5562==    by 0x4EA2EE5: printf (printf.c:33)
==5562==    by 0x1086BC: main (test.c:6)
==5562== 
==5562== Conditional jump or move depends on uninitialised value(s)
==5562==    at 0x4E9AB1C: vfprintf (vfprintf.c:1642)
==5562==    by 0x4EA2EE5: printf (printf.c:33)
==5562==    by 0x1086BC: main (test.c:6)
==5562== 
0
==5562== 
==5562== HEAP SUMMARY:
==5562==     in use at exit: 40 bytes in 1 blocks
==5562==   total heap usage: 2 allocs, 1 frees, 1,064 bytes allocated
==5562== 
==5562== LEAK SUMMARY:
==5562==    definitely lost: 40 bytes in 1 blocks
==5562==    indirectly lost: 0 bytes in 0 blocks
==5562==      possibly lost: 0 bytes in 0 blocks
==5562==    still reachable: 0 bytes in 0 blocks
==5562==         suppressed: 0 bytes in 0 blocks
==5562== Rerun with --leak-check=full to see details of leaked memory
==5562== 
==5562== For counts of detected and suppressed errors, rerun with: -v
==5562== Use --track-origins=yes to see where uninitialised values come from
==5562== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)

==5562==   total heap usage: 2 allocs, 1 frees, 1,064 bytes allocated
观察此行,可以发现堆内存分配了 2 次(共 1064 字节),但只释放了 1 次,导致程序退出时仍有 1 个内存块(40 字节)未被回收。
==5562==    definitely lost: 40 bytes in 1 blocks
此行意为内存完全丢失,没有任何指针指向该内存空间,必须修复

==5562== Use of uninitialised value of size 8
==5562==    at 0x4E9683B: _itoa_word (_itoa.c:179)
==5562==    by 0x4E99EDD: vfprintf (vfprintf.c:1642)
==5562==    by 0x4EA2EE5: printf (printf.c:33)
==5562==    by 0x1086BC: main (test.c:6)

此段意为程序读取了一个 8 字节(指针的大小)的垃圾数据。
原因在于test.c的第六行打印了一个未初始化的变量导致 printf 在解析这个垃圾数字时触发了错误。

进阶参数

例:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./app arg1 arg2
valgrind --leak-check=full ./app arg1 arg2
参数解释:
--leak-check=full:泄漏细节更全
--show-leak-kinds=all:显示 definitely/indirectly/possibly/ still reachable
--track-origins=yes:追踪未初始化值来源(慢一些,但非常值)
例:valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes  ./a.out

==5626== HEAP SUMMARY:
==5626==     in use at exit: 40 bytes in 1 blocks
==5626==   total heap usage: 2 allocs, 1 frees, 1,064 bytes allocated
==5626== 
==5626== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5626==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5626==    by 0x10869B: main (test.c:5)
==5626== 
==5626== LEAK SUMMARY:
==5626==    definitely lost: 40 bytes in 1 blocks
==5626==    indirectly lost: 0 bytes in 0 blocks
==5626==      possibly lost: 0 bytes in 0 blocks
==5626==    still reachable: 0 bytes in 0 blocks
==5626==         suppressed: 0 bytes in 0 blocks
==5626== 
==5626== For counts of detected and suppressed errors, rerun with: -v
==5626== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)

这里展示结果中的一段内容,可以发现给出的信息更加详细了

小结:

编译:
gcc -g -O0 -o app main.c

运行:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./app

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值