`
hulianwang2014
  • 浏览: 726204 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

使用valgrind来发现内存泄漏和非法内存操作

 
阅读更多

原文地址:http://www.cprogramming.com/debugging/valgrind.html

翻译难免会因个人水平原因而有不准确的地方,请大家多批评指正,上面是原文链接,大家也可以直接去看看。

valgrind是Linux平台一个多用途的代码审查和内存调试工具。它可以在valgrind自己的环境中运行你的程序,监控malloc/free,(new/delete for C++)等内存调用。如果你用了未初始化的内存,数组越界写入,或者忘了free一个指针,valgrind会检测到它们。由于这些都是一些日常最普通的问题,这篇文章就主要介绍如何用valgrind来发现这类简单的内存问题,虽然valgrind可以做的更多。


对windows使用者来说,如果你没有对linux机器的访问权限,或者你想开发windows程序,那么你可能对IBM的Purity软件更有兴趣,Purity在检测内存问题方面与valgrind功能类似,你可以自己去下载它。


获取Valgrind

如果你正在运行linux,而没有安装valgrind,那么你可以从Valgrind download page下载。

安装很简单,只需要解压就可以了。(XYZ在下面的例子中是版本号的意思)

bzip2 -d valgrind-XYZ.tar.bz2
tar -xf valgrind-XYZ.tar
上面的操作会创建一个目录,名字为valgrind-XYZ,切换到这个目录,运行下面的命令

./configure
make
make install
现在你已经安装了valgrind,让我们看下怎么使用它


使用Valgrind查找内存泄漏

内存泄漏是最难检测的bug之一,因为直到你用完了内存而有一个malloc失败,它不会表现出任何外在的问题。实际上,当我们使用C/C++这类没有垃圾回收机制的语言来工作的时候,几乎一半的时间会花费在正确处理free内存的问题上。如果你的程序运行足够长的时间并且运行到了那个代码分支,即使一个错误也是代价巨大的。


当你用valgrind运行你的代码的时候,你需要指定使用valgrind的什么工具;简单地运行一下valgrind你就会得到当前的列表。在这篇文章中,我们主要使用memcheck工具,memcheck工具可以保证我们正确的内存使用。不加其他参数,valgrind会打印出调用call和malloc的一个概括信息(注意18490是我系统上的process id;在不同的运行时,它是不同的)

% valgrind --tool=memcheck program_name
...
=18515== malloc/free: in use at exit: 0 bytes in 0 blocks.
==18515== malloc/free: 1 allocs, 1 frees, 10 bytes allocated.
==18515== For a detailed leak analysis,  rerun with: --leak-check=yes
如果你有一处内存泄漏,那么alloc和free的数目就会不同(你不能用free去释放一块属于多个alloc的内存)。我们稍后会回来看这个概况,但是现在,注意一些errors被制止了,因为它们是来自标准库的,而不是来自你的代码。


如果alloc和free的数目不同,你需要用选项--leak-check来重新运行程序。这会向你展示所有的没有相匹配的free的malloc/new等调用。

为了说明,我用一个简单的程序,我编译成可执行文件"example1"

#include <stdlib.h>
int main()
{
    char *x = malloc(100); /* or, in C++, "char *x = new char[100] */
    return 0;
}
% valgrind --tool=memcheck --leak-check=yes example1

这会产生关于上面展示的程序的一些信息,生成一份列表,调用malloc但是没有相应的free。

==2116== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2116==    at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2116==    by 0x804840F: main (in /home/cprogram/example1)
这并没有按照我们希望的那样告诉我们太多,尽管我们知道这个内存泄漏是发现在main中对malloc的调用,但是我们不知道行号。这个问题是因为我们编译的时候没有用gcc的-g选项,这个选项会添加调试符号。因此我们重新编译,得到下面更有用的信息。

==2330== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2330==    at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2330==    by 0x804840F: main (example1.c:5)
现在我们知道确切的行号,在哪里这块泄漏的内存被分配。尽管想要跟踪下去到free的时候,还是个问题,但是至少我们知道从哪开始查起。并且,既然对每一处malloc或new的调用,你都有计划如何处理这块内存,知道内存在哪里泄漏会让你知道从哪里开始查找问题。


有时,选项--leak-check=yes不会向你展示所有的内存泄漏。要找到所有的不成对的对free和new的调用,你需要使用选项--show-reachable=yes。它的输出基本是相同的,但是它会向你展示更多unfreed的内存。


使用Valgrind发现非法指针使用

Valgrind通过memcheck工具发现非法堆内存的使用。例如,如果你用malloc或new分配一个数组,然后尝试访问数组的边界外位置:

char *x = malloc(10);
x[10] = 'a';
Valgrind会检测到。例如,用valgrind运行下面的程序example2

#include <stdlib.h>

int main()
{
    char *x = malloc(10);
    x[10] = 'a';
    return 0;
}
运行方法:

valgrind --tool=memcheck --leak-check=yes example2
结果为:

==9814==  Invalid write of size 1
==9814==    at 0x804841E: main (example2.c:6)
==9814==  Address 0x1BA3607A is 0 bytes after a block of size 10 alloc'd
==9814==    at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==9814==    by 0x804840F: main (example2.c:5)
上面的结果告诉我们:我们正在越界使用一个被分配了10bytes空间的指针,结果有一个‘Invalid write’。如果我们尝试从那块内存读数据,我们会被将被警告'Invalid read of size X',此处的X是我们尝试读取的内存大小(对char类型来说,它是1,对int就是2或者4).通常,Valgrind会打印出函数调用的堆栈信息,我们就会确切地知道错误在哪发生。


使用Valgrind检测未初始化的变量使用

Valgrind还有一个用途,它可以检测到在条件语句中使用未初始化的值。尽管你应该习惯在创建一个变量的时候进行初始化,但是Valgrind会帮助你发现那些你忘记的地方。例如,运行下面example3的代码:

#include <stdio.h>

int main()
{
    int x;
    if(x == 0)
    {
        printf("X is zero"); /* replace with cout and include 
                                iostream for C++ */
    }
    return 0;
}
结果为:

==17943== Conditional jump or move depends on uninitialised value(s)
==17943==    at 0x804840A: main (example3.c:6)
Valgrind会足够聪明,知道一个变量是否被用一个未初始化的变量赋值,例如,下面的代码:

#include <stdio.h>

int foo(int x)
{
    if(x < 10)
    {
        printf("x is less than 10\n");
    }
}

int main()
{
    int y;
    foo(y);
}
结果如下:

==4827== Conditional jump or move depends on uninitialised value(s)
==4827==    at 0x8048366: foo (example4.c:5)
==4827==    by 0x8048394: main (example4.c:14)
你可能会认为问题出在foo函数中,堆栈信息也不重要。但是,由于main传了一个未初始化的值给foo函数(你从来没有给y赋值),那么我们查找问题并跟踪变量的赋值堆栈,直到我们发现了一个未初始化的变量。

这只会在你的程序走到那个分支的时候帮助你,尤其是条件语句。所以确保在测试的时候能够让程序走过所有的分支。


Valgrind能够发现的其他问题

Valgrind会检测到其他的一些不恰当的内存使用:如果你free一个指针两次,Valgrind会为你检测到;你会得到下面错误:

Invalid free()
并跟随一些相关的堆栈

Valgrind也会检测到释放内存时选择了错误的方法。例如,在C++中,有3中基本的释放动态内存的方法:free,delete,delete[]。free函数只跟malloc匹配,delete只跟new匹配,delete[]只跟new[]匹配。(尽管有些编译器会为你处理此类用错delete的情况,但是不能保证所有的编译器都能,它不是变准要求的)。

如果你触发了这类问题,你会得到错误:

Mismatched free() / delete / delete []

这是必须要修复的,即使你的程序碰巧可以工作。


Valgrind不能发现的东西

Valgrind不能检查静态数组的边界(在栈上分配的空间)。因此,如果你在你的函数中声明一个数组

int main()
{
    char x[10];
    x[11] = 'a';
}
那么,Valgrind不会警告你的!一个可能用于测试目的的解决方案是在你需要做边界检测的地方转换你的静态数组为从堆上动态分配内存,但是这会产生很多unfreed的内存。


其他更过的警告信息

Valgrind的缺点是什么呢?它会消耗更多的内存--最大两倍于你源程序需要的内存。如果你在检测一个很大的内存问题,那这可能会导致一些问题。它会需要更长的时间去运行你的程序。这通常不应该有什么问题,并且也只是在你测试的时候有影响而已。但是如果你正在运行一个本来已经很慢的程序,那么这也可能会是个问题。


总结

Valgrind是一个对x86和AMD64结构的一个工具,运行在Linux环境下。它允许程序员在它的环境下运行程序,因此可以检测不成对的malloc和其他使用非法内存(例如未初始化的内存)的问题或者非法内存操作(例如重复free同一块内存,调用错误的析构函数)。Valgrind不能检测静态内存问题。


水平有限,如果有朋友发现错误,欢迎留言交流。
转载请保留本文链接,如果觉得我的文章能帮到您,请顶一下。,谢谢。



分享到:
评论

相关推荐

    Valgrind3.6.0一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具

    它能够检查程序在运行时的内存分配和释放操作,帮助开发者发现非法内存访问(如使用未初始化的内存、访问已释放的内存、越界访问等)和内存泄漏问题。Valgrind通过模拟硬件执行来监控程序的内存操作,使得开发者可以...

    Valgrind简介和使用方法

    通过Valgrind,开发者能够发现和修复程序中的内存泄漏、使用未初始化的内存、访问已释放内存等常见问题,从而提高程序的稳定性和可靠性。Valgrind的强大之处在于它能够提供详细的错误报告,帮助开发者快速定位问题...

    应用-Valgrind-发现-Linux-程序的内存问题.doc

    Valgrind 是一款强大的Linux内存调试工具,特别适用于检测程序中的内存管理问题,如内存泄漏、非法内存访问等。在Linux运维和服务器管理中,它是一个不可或缺的实用工具,可以帮助开发者和运维人员找出那些难以通过...

    valgrind安装与使用

    * Memcheck:检测内存泄漏和非法内存访问。 * Cachegrind:检测 CPU 缓存的使用情况。 * Helgrind:检测多线程程序中的数据竞争。 这些工具可以单独使用,也可以组合使用以检测不同的错误。 Valgrind 是一个功能...

    内存泄露检查工具

    内存泄露是编程中一个常见的问题,特别是在C++和C...它们帮助开发者及时发现和修复内存管理问题,避免因内存泄露导致的性能下降或程序崩溃。正确使用这些工具,可以显著提升编程效率,确保软件的健壮性和长期稳定运行。

    Linux内存调试工具Valgrind -PDF

    Valgrind会输出具体的内存泄漏位置及相关信息,帮助开发者定位问题。 ##### 2. 无效指针示例 考虑另一个C程序,该程序试图访问一个超出分配内存范围的元素: ```c #include int main() { char *x = malloc(10);...

    Linux C语言程序内存泄漏检测工具-Valgrind.doc

    Linux C语言程序内存泄漏检测工具-Valgrind Valgrind 是一款 Linux 下的免费内存调试工具包,...Valgrind 是一种功能强大且实用的内存泄漏检测工具,对于 Linux 操作系统下的 C 语言程序开发和调试具有重要的意义。

    valgrind 的使用简介使用的代码

    1. **memcheck**:这是Valgrind的核心工具,用于检测内存错误,包括内存泄漏、未初始化的内存访问和无效的内存操作。 2. **callgrind**:用于性能分析,记录函数调用关系并计算每行代码的执行次数,帮助优化代码。 ...

    valgrind教程

    它能够帮助开发者发现导致程序崩溃或行为异常的各种内存问题,例如内存泄漏、非法访问等。 #### 二、Valgrind的组成部分 Valgrind文档主要由以下六个逻辑上独立的部分组成: 1. **Valgrind快速入门指南**:为初学...

    用Valgrind和GDB进行C-C++项目的性能优化与调试.md

    首先,Valgrind 是一套强大的动态分析工具集,可检测内存泄漏、非法内存访问和数据竞争等问题;其中,Memcheck、Massif 和 Cachegrind 是常用工具,用于内存和性能分析。GDB 是 GNU 项目的调试器,支持设置断点、...

    valgrind的使用方法-详细手册

    通过Valgrind,开发者可以深入地了解程序在运行时的内存使用情况,例如动态内存分配与释放(C语言中的`malloc`/`free`或C++中的`new`/`delete`)。利用Valgrind提供的工具,可以自动化地检测出各种内存管理和多线程...

    Valgrind_manual Valgrind手册文档

    Valgrind提供的工具可以帮助程序员发现程序中的内存泄漏、越界访问、未初始化的内存读取、不当的内存释放等问题,从而使得程序运行更加稳定和高效。 在Valgrind的最新手册中,包含了六个部分的文档,分别是Valgrind...

    valgrind_安装使用说明-Howard.doc

    它包含了一系列的子工具,能够帮助开发者发现并解决程序中常见的问题,如内存泄漏、非法内存访问以及性能优化等。 首先,让我们来看看如何安装Valgrind。安装过程相对简单,一般包括以下几个步骤: 1. 从Valgrind...

    valgrind-3.17.0.tar.gz

    总之,Valgrind-3.17.0是Linux环境下开发C和C++程序的得力助手,它能帮助开发者发现和解决内存管理问题,提高代码质量,防止因内存泄漏和多线程错误导致的系统不稳定。对于任何在Linux系统上开发内存敏感应用的人来...

    valgrind_manual.pdf

    它可以帮助开发者发现程序运行时的内存泄漏、内存覆盖、数组越界访问、未初始化内存使用等常见问题。Valgrind包括多个工具,其中最著名的是Memcheck工具。此外,它还提供了Callgrind、Cachegrind和Helgrind等工具来...

    valgrind manual

    Valgrind的核心功能之一是Memcheck工具,它能够检测出C/C++程序中常见的内存相关错误,如内存泄漏、非法读写等问题,这些问题可能导致程序崩溃或行为异常。 #### 二、Valgrind文档结构 Valgrind文档分为六个逻辑...

    valgrind-sample

    2. **运行程序**:使用Valgrind运行程序,例如,使用`valgrind --leak-check=yes ./your_program`来检测内存泄漏。 3. **解读输出**:Valgrind会生成详细的错误报告,包括错误类型、发生位置及可能的原因,开发者需...

    走下神坛的内存调试器--定位多线程内存越界问题实践总结[整理].pdf

    使用 valgrind 可以检查内存问题,程序不需要重新编译,只需要使用 valgrind 来启动。valgrind 提供了各种检查工具,如 Memcheck、Helgrind 等,可以检测内存泄露、野指针、数组越界等问题。 知识点3:mprotect 的...

Global site tag (gtag.js) - Google Analytics