Jade Dungeon

valgrind 简单使用。 valgrind 是一款 memorycheck 工具,用于 c/c++ 程序的内存检查/调试。 0. 为了使用 valgrind 编译程序时要使用 gcc 的 -g 编译选项,链接libc 的 debug 版本, 自动链接,但是要求有, 如果没有 valgrind 不能正常启动内存检查. 程序用到的其他 C 库也要有 debug 版本的。 也可以使用 gcc 的 -O0 编译选项。据说使用了更好。(大写 O, 数字 0) 1. Memorycheck 是 valgrind 的默认工具,--leak-check 选项可以打开 valgrind 详细的 memory leak 探测工具。 $ gcc -O0 -g example.c -o example $ valgrind --leack-check=yes ./example arg1 arg2 2. valgrind 的输出。 下面是一个正常分配并正常释放内存的程序用 valgrind 调试的输出:

  1. 733 是 process id, 无关紧要; ==733== Memcheck, a memory error detector ==733== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==733== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
  2. 以下是重要信息; ==733== Command: ./mkdir_t 1/2/3/4 ==733==
  3. 这里可能会有程序的 stdout/stderr 输出; ==733==
  4. 内存使用状况的汇总; ==733== HEAP SUMMARY: ==733== in use at exit: 0 bytes in 0 blocks ==733== total heap usage: 3 allocs, 3 frees, 18 bytes allocated ==733== ==733== All heap blocks were freed -- no leaks are possible ==733==
  5. 错误信息汇总;(这里没有错误) ==733== For counts of detected and suppressed errors, rerun with: -v ==733== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) 下面是一个越界使用了动态分配的内存, 没有释放动态分配内存的程序的输出; 程序名字是 example, 程序文件名后面的数字说明了 memory allocated 之类的操作的 代码在文件中的位置, 或者说哪里有 memory allocated.
  6. Invalid write 指示了 memory overrun; ==1058== Invalid write of size 4
  7. 这里是堆栈跟踪(stack tracking), stack tracking 从下到上读比较容易; ==1058== at 0x40054A: func (example.c:15) ==1058== by 0x400524: main (example.c:8) ==1058== Address 0x51bc068 is 0 bytes after a block of size 40 alloc'd
  8. 这里也是 stack tracking 信息,比上面的更深了一层,
  9. 已经到了 malloc 是内存分配的情况; ==1058== at 0x4C29554: malloc (vg_replace_malloc.c:298) ==1058== by 0x40053D: func (example.c:14) # 后面的数字指示了代码所在行 ==1058== by 0x400524: main (example.c:8) ==1058== ==1058==
  10. 内存(HEAP),使用汇总; ==1058== HEAP SUMMARY: ==1058== in use at exit: 40 bytes in 1 blocks
  11. N allocs, N frees 才正常, 40 bytes allocated 指示分配了多少字节内存; ==1058== total heap usage: 1 allocs, 0 frees, 40 bytes allocated ==1058==
  12. definitely lost 指示了内存泄漏(memory leak); ==1058== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==1058== at 0x4C29554: malloc (vg_replace_malloc.c:298) ==1058== by 0x40053D: func (example.c:14) ==1058== by 0x400524: main (example.c:8) ==1058==
  13. memory leak 汇总;
  14. definitely, indirectly, possibly 是三种 memory leadk 方式. ==1058== LEAK SUMMARY: ==1058== definitely lost: 40 bytes in 1 blocks # 明确地 ==1058== indirectly lost: 0 bytes in 0 blocks # 间接地 ==1058== possibly lost: 0 bytes in 0 blocks # 可能性很大地 ==1058== still reachable: 0 bytes in 0 blocks ==1058== suppressed: 0 bytes in 0 blocks ==1058==
  15. 错误信息汇总 ==1058== For counts of detected and suppressed errors, rerun with: -v ==1058== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)

3. If the stack trace is not big enough, use the --num-callers option to make it bigger. 4. valgrind 也报告"使用了未初始化变量错误(uninitialished value)"的情况。 使用 --track-origins=yes 可以看到有关于此的更多的扩展信息, 但是这样也会让程序变得更慢. 5. Memcheck cannot detect every memory error your program has. For example, it can't detect out-of-range reads or writes to arrays that are allocated statically or on the stack. But it should detect many errors that could crash your program (eg. cause a segmentation fault).