使用Valgrind发现Linux下C程序的内存问题


=Start=

缘由:

学习使用Valgrind的Memcheck工具发现Linux下C程序中的内存问题。

正文:

参考解答:
Valgrind是什么?

Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其他工具;而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。Valgrind包括如下一些工具:

  1. Memcheck。这是Valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。
  2. Callgrind。它主要用来检查程序中函数调用过程中出现的问题。
  3. Cachegrind。它主要用来检查程序中缓存使用出现的问题。
  4. Helgrind。它主要用来检查多线程程序中出现的竞争问题。
  5. Massif。它主要用来检查程序中堆栈使用中出现的问题。
  6. Extension。可以利用core提供的功能,自己编写特定的内存调试工具。
Valgrind Memcheck的检测方法和原理:

Memcheck 能够检测出内存问题,关键在于其建立了两个全局表:

  • Valid-Value 表

对于进程的整个地址空间中的每一个字节(byte),都有与之对应的 8 个 bits;对于 CPU 的每个寄存器,也有一个与之对应的 bit 向量。这些 bits 负责记录该字节或者寄存器值是否具有有效的、已初始化的值。

  • Valid-Address 表

对于进程整个地址空间中的每一个字节(byte),还有与之对应的 1 个 bit,负责记录该地址是否能够被读写。

检测原理:

  • 当要读写内存中某个字节时,首先检查这个字节对应的 A bit。如果该A bit显示该位置是无效位置,memcheck 则报告读写错误。
  • 内核(core)类似于一个虚拟的 CPU 环境,这样当内存中的某个字节被加载到真实的 CPU 中时,该字节对应的 V bit 也被加载到虚拟的 CPU 环境中。一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序输出,则 memcheck 会检查对应的V bits,如果该值尚未初始化,则会报告使用未初始化内存错误。
Valgrind Memcheck可发现的常见内存问题:
  1. 使用未初始化的内存(对于位于程序中不同段的变量,其初始值是不同的,全局变量和静态变量初始值为0,而局部变量和动态申请的变量,其初始值为随机值。如果程序使用了为随机值的变量,那么程序的行为就变得不可预期。)
  2. 内存读写越界(访问了你不应该/没有权限访问的内存地址空间,比如访问数组时越界;对动态内存访问时超出了申请的内存大小范围。)
  3. 内存覆盖(比如 strcpy, strncpy, memcpy, strcat 等,这些函数有一个共同的特点就是需要设置源地址 (src),和目标地址(dst),src 和 dst 指向的地址不能发生重叠,否则结果将不可预期。)
  4. 动态内存管理错误(申请和释放不一致/申请和释放不匹配/释放后仍然读写)
  5. 内存泄露(在一个单独的函数中,每个人的内存泄露意识都是比较强的。但很多情况下,我们都会对malloc/free 或new/delete做一些包装,以符合我们特定的需要,无法做到在一个函数中既使用又释放。内存泄露最容易发生的地方:即两个部分的接口部分,一个函数申请内存,一个函数释放内存。并且这些函数由不同的人开发、使用,这样造成内存泄露的可能性就比较大了。这需要养成良好的单元测试习惯,将内存泄露消灭在初始阶段。)
Valgrind Memcheck的使用方法:

利用valgrind调试内存问题,不需要重新编译源程序,它的输入就是二进制的可执行程序。调用Valgrind的通用格式是:

$ valgrind [valgrind-options] your-prog [your-prog-options]

Valgrind 的参数分为两类,一类是 core 的参数,它对所有的工具都适用;另外一类就是具体某个工具如 memcheck 的参数。Valgrind 默认的工具就是 memcheck,也可以通过 `–tool=tool_name` 指定其他的工具。Valgrind 提供了大量的参数满足你特定的调试需求,具体可参考其用户手册。

$ valgrind [valgrind-options] your-prog [your-prog-options]
$ valgrind ./a.out
$ valgrind --tool=memcheck ./a.out
$ valgrind --tool=memcheck --leak-check=full ./a.out # 如果我们仅仅用默认方式执行,valgrind只报告内存泄漏,但没有显示具体代码中泄漏的地方,因此我们需要使用“--leak-check=full”选项
参考链接:

在 Linux 平台中调试 C/C++ 内存泄漏方法
https://www.ibm.com/developerworks/cn/linux/l-cn-memleak/index.html

应用 Valgrind 发现 Linux 程序的内存问题
https://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/

如何使用Valgrind memcheck工具进行C/C++的内存泄漏检测
https://www.oschina.net/translate/valgrind-memcheck
http://www.thegeekstuff.com/2011/11/valgrind-memcheck/

Valgrind使用说明
http://www.cnblogs.com/wangkangluo1/archive/2011/07/20/2111248.html

5.3. 使用 Valgrind 简要描述内存使用
https://access.redhat.com/documentation/zh-CN/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-memory-valgrind.html

VALGRIND使用:检测内存泄漏
http://reborncodinglife.com/2016/11/07/how-to-check-mem-leak/

C++测试工具Valgrind
http://dasheyuan.com/post/cpp-test-tool-valgrind/

valgrind memcheck使用方法及效果
http://windmissing.github.io/linux/2016-02/valgrind-memcheck.html

Valgrind使用小记
http://talk.acgtea.com/use-valgrind-to-check-mem/

valgrind安装和使用(一)
http://www.ccyuki.com/valgrindan-zhuang-he-shi-yong-yi/

gcc/gdb/gprof/gcov/valgrind使用
http://www.udpwork.com/item/13025.html

代码测试、调试与优化
https://github.com/tinyclub/open-c-book/blob/master/zh/chapters/02-chapter9.markdown

Using Valgrind to Find Memory Leaks and Invalid Memory Use
http://www.cprogramming.com/debugging/valgrind.html

The Valgrind Quick Start Guide
http://valgrind.org/docs/manual/quick-start.html
http://valgrind.org/docs/manual/QuickStart.html

Valgrind User Manual
http://valgrind.org/docs/manual/manual.html

内存调试技巧
https://www.ibm.com/developerworks/cn/aix/library/au-memorytechniques.html

=END=


《 “使用Valgrind发现Linux下C程序的内存问题” 》 有 2 条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注