查找内存泄露的工具

所有使用动态内存分配(dynamic memory allocation)的程序都有机会遇上内存泄露(memory leakage)问题,在Linux里有三种常用工具来检测内存泄露的情況,包括:

  1. mtrace
  2. dmalloc
  3. memwatch

1. mtrace

from:

mtrace是三款工具之中是最简单易用的,mtrace是一个C函數,在<mcheck.h>里声明及定义,函数原型为:

    void mtrace(void);

 

其实mtrace是类似malloc_hook的 malloc handler,只不过mtrace的handler function已由系统为你写好,但既然如此,系统又怎么知道你想将malloc/free的记录写在哪里呢?为此,调用mtrace()前要先设置 MALLOC_TRACE环境变量:

    #include <stdlib.h>
    ....
    setenv("MALLOC_TRACE", "output_file_name", 1);
    ...

 

「output_file_name」就是储存检测结果的文件的名称。

但是检测结果的格式是一般人无法理解的,而只要有安装mtrace的话,就会有一名为mtrace的Perl script,在shell输入以下指令:

    mtrace [binary] output_file_name

 

就会将output_file_name的內容转化成能被理解的语句,例如「No memory leaks」,「0x12345678 Free 10 was never alloc」诸如此类。

例如以下有一函数:(暂且放下single entry single exit的原则)

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <mcheck.h>
    int main() {
        char *hello;
   
        setenv("MALLOC_TRACE", "output", 1);
        mtrace();
        if ((hello = (char *) malloc(sizeof(char))) == NULL) {
            perror("Cannot allocate memory.");
            return -1;
        }

        return 0;
    }

 

执行后,再用mtrace 将结果输出:

    - 0x08049670 Free 3 was never alloc'd 0x42029acc
    - 0x080496f0 Free 4 was never alloc'd 0x420dc9e9
    - 0x08049708 Free 5 was never alloc'd 0x420dc9f1
    - 0x08049628 Free 6 was never alloc'd 0x42113a22
    - 0x08049640 Free 7 was never alloc'd 0x42113a52
    - 0x08049658 Free 8 was never alloc'd 0x42113a96

    Memory not freed:
    -----------------
       Address     Size     Caller
    0x08049a90      0x1  at 0x80483fe

 

最后一行标明有一个大小为1 byte的内存尚未释放,大概是指「hello」吧。

    若我们把该段内存释放:

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <mcheck.h>
    int main() {
        char *hello;
   
        setenv("MALLOC_TRACE", "output", 1);
        mtrace();
        if ((hello = (char *) malloc(sizeof(char))) == NULL) {
            perror("Cannot allocate memory.");
            return -1;
        }

        free(hello);
        return 0;
    }

 

结果如下:

    - 0x080496b0 Free 4 was never alloc'd 0x42029acc
    - 0x08049730 Free 5 was never alloc'd 0x420dc9e9
    - 0x08049748 Free 6 was never alloc'd 0x420dc9f1
    - 0x08049668 Free 7 was never alloc'd 0x42113a22
    - 0x08049680 Free 8 was never alloc'd 0x42113a52
    - 0x08049698 Free 9 was never alloc'd 0x42113a96
    No memory leaks.

 

mtrace的原理是记录每一对malloc-free的执行,若每一个malloc都有相应的free,则代表没有内存泄露,对于任何非malloc/free情況下所发生的内存泄露问题,mtrace并不能找出来。

但是mtrace在Red Hat 9的安装包并不提供,必须自己编译才能用哦。

wget --passive-ftp ftp://rpmfind.net/linux/redhat/9... -2.3.2-11.9.src.rpm
  rpm -ivh glibc*.src.rpm
  cd /usr/src/redhat/SPECS/
  rpmbuild -ba glibc-9.spec
  cd /var/tmp/glibc-2.3.2-root/usr/bin/
  cp mtrace /usr/bin/

 

2. 使用dmalloc&valgrind检测内存泄露

from http://blog.csdn.net/Dansley/archive/2009/06/26/4301975.aspx

 

dmalloc是一个简单易用的C/C++内存leak检查工具,以一个运行库的方式发布。dmalloc能够检查出直到程序运行结束还没有释放的内存,并且能够精确指出在哪个源文件的第几行。

dmalloc 主页: http://dmalloc.com

支持的平台:AIX, BSD/OS, DG/UX, Free/Net/OpenBSD, GNU/Hurd, HPUX, Irix, Linux, MS-DOG, NeXT, OSF, SCO, Solaris, SunOS, Ultrix, Unixware, Windoze, and even Unicos on a Cray T3E. 最新版本: 5.5.2.

安装:下载 http://dmalloc.com/releases/dmalloc-5.5.2.tgz

1. $tar zxvf dmalloc-5.5.2.Tgz  2.$cd dmalloc-5.5.2   3. $./configure  4.$make;sudo make install

设置环境变量:

terminal输入export DMALLOC_OPTIONS=log=logfile, debug=0x3(in Bash)/export DMALLOC_OPTIONS=debug 0x3,log=logfile(in Csh).或者在terminal输入dmalloc -l logfile -i 100 low,然后重新登陆用户,或者执行: source ~/.bashrc source ~/.profile

在源文件中添加下面的C代码:

#ifdef DMALLOC

#include "dmalloc.h"

#endif

值得注意的是:要在每一个.C文件里面添加,而且必须添加在所包含的头文件最后一行!

编译使用的CFLAGS: -DDMALLOC -DDMALLOC_FUNC_CHECK

如: gcc -DDMALLOC -DDMALLOC_FUNC_CHECK (-ldmalloc) dm_test.c

执行:   ./a.out

运行上面的命令会在当前目录下生成 logfile文件,打开logfile,那么哪个地方的内存leak就一目了然了。

例子:

      #include <stdio.h>

      #include <stdlib.h>

      #include <string.h>

      #ifdef DMALLOC

      #include <dmalloc.h>

      #endif

      int main(int argc, char **argv)

      {

          char *string;

          string = malloc(sizeofchar);

          string = malloc(sizeof(int*));

          return 0;

      }

    Dmalloc的局限性:

1Dmalloc只能检测堆上内存,对栈内存和静态内存无能为力。

2. dmalloc只用于利用malloc申请的内存,对使用sbrk()mmap()分配的内存无能为力。

3. dmalloc不能用于检测读写没有申请的或者没有初始化的内存,也不能检测写只读内存。

 

 

Valgrind是一个GPL的软件,用于LinuxFor x86, amd64 and ppc32)程序的内存调试和代码剖析。你可以在它的环境中运行你的程序来监视内存的使用情况,比如C 语言中的mallocfree或者 C++中的new delete。使用Valgrind的工具包,你可以自动的检测许多内存管理和线程的bug,避免花费太多的时间在bug寻找上,使得你的程序更加稳固。
Valgrind的主要功能
Valgrind工具包包含多个工具,如Memcheck,Cachegrind,Helgrind, CallgrindMassif。下面分别介绍个工具的作用:
 
 
Memcheck 工具主要检查下面的程序错误:
 
 
使用未初始化的内存 (Use of uninitialised memory)
使用已经释放了的内存 (Reading/writing memory after it has been freed)
使用超过 malloc分配的内存空间(Reading/writing off the end of mallocd blocks)
对堆栈的非法访问 (Reading/writing inappropriate areas on the stack)
申请的空间是否有释放 (Memory leaks  where pointers to mallocd blocks are lost forever)
malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
srcdst的重叠(Overlapping src and dst pointers in memcpy() and related functions)
Callgrind
Callgrind收集程序运行时的一些数据,函数调用关系等信息,还可以有选择地进行cache 模拟。在运行结束时,它会把分析数据写入一个文件。callgrind_annotate可以把这个文件的内容转化成可读的形式。
 
 
Cachegrind
它模拟 CPU中的一级缓存I1,D1L2二级缓存,能够精确地指出程序中 cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数。这对优化程序有很大的帮助。
 
 
Helgrind
它主要用来检查多线程程序中出现的竞争问题。Helgrind 寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方,而且会导致难以发掘的错误。Helgrind实现了名为” Eraser” 的竞争检测算法,并做了进一步改进,减少了报告错误的次数。
 
 
Massif
堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。
 
 
Valgrind 安装
1、 到www.valgrind.org下载最新版valgrind-3.2.3.tar.bz2
2、 解压安装包:tar jxvf valgrind-3.2.3.tar.bz2
3、 解压后生成目录valgrind-3.2.3
4 cd valgrind-3.2.3
5 ./configure
6make;sudo make install
 
 
注意:不要移动Valgrind到一个与--prefix指定的不一样的目录,这将导致一些莫名其妙的错误,大多数在Valgrind处理/fork/exec调用时。
 
 
1.检查内存错误:
例如我们原来有一个程序test,这是一个用gcc g参数编译的程序,运行它需要:
#./a.out
如果我们想用valgrind的内存检测工具,我们就要用如下方法调用:
#valgrind --leak-check=full --show-reachable=yes --trace-children= yes   ./a.out 
logfile加上会好些,程序在执行期间stderr会有一些输出。加上logfile的话可以像dmalloc那样打开logfile来查看错误信息。
 
 
其中--leak-check=full 指的是完全检查内存泄漏,--show-reachable=yes是显示内存泄漏的地点,--trace-children=yes是跟入子进程。
 
 
如果您的程序是会正常退出的程序,那么当程序退出的时候valgrind自然会输出内存泄漏的信息。如果您的程序是个守护进程,那么也不要紧,我们 只要在别的终端下杀死memcheck进程(因为valgrind默认使用memcheck工具,就是默认参数—tools=memcheck):
#killall memcheck
这样我们的程序(./a.out)就被kill
 
 
2.检查代码覆盖和性能瓶颈:
我们调用valgrind的工具执行程序:
#valgrind --tool=callgrind ./sec_infod
 
 
会在当前路径下生成callgrind.out.pid(当前生产的是callgrind.out.19689),如果我们想结束程序,可以:
#killall callgrind
然后我们看一下结果:
#callgrind_annotate --auto=yes callgrind.out.19689   >log
#vim log
 
 
3.Valgrind使用参数
          --log-fd=N 默认情况下,输出信息是到标准错误stderr,也可以通过—log-fd=8,输出到描述符为8的文件
          --log-file=filename将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID。可以通过--log- file exactly=filename指定就输出到filename文件。
          --log-file-qualifier=<VAR>,取得环境变量的值来做为输出信息的文件名。如—log-file- qualifier=$FILENAME
          --log-socket=IP:PORT 也可以把输出信息发送到网络中指定的IP:PORT
          --error-limit=no 对错误报告的个数据进行限制,默认情况不做限制
          --tool=<toolname> [default: memcheck]
--tool=memcheck:要求用memcheck这个工具对程序进行分析
     --leak-ckeck=yes 要求对leak给出详细信息
     --trace-children=<yes|no> [default: no]跟踪到子进程里去,默认请况不跟踪
     --xml=<yes|no> [default: no]将信息以xml格式输出,只有memcheck可用
     --gen-suppressions=<yes|no|all> [default: no]如果为yesvalgrind会在每发现一个错误便停下让用户做选择是继续还是退出
 
 
更多选项请参看: http://www.valgrind.org/docs/manual/manual-core.html可以把一些默认选项编辑在 ~/.valgrindrc文件里。
 
 
这里使用valgrindmemcheckcallgrind两个工具的用法,其实valgrind还有几个工具:“cachegrind,用于检查缓存使用的;“helgrind”用于检测多线程竞争资源的,等等。
 dmalloc相比,Valgrind使用范围更广,它不但能够检测出堆内存的泄露,对线程间使用共同资源所带来的内存泄露也能够察觉出来,但是valgrind所产生的log信息往往比dmalloc多得多,有时候就是一千多行的log信息,让人看到就头痛。
3.memwatch查看linux内存泄露
1. 介绍
       memwatch简单易用,能检测未被释放的内存,释放多次的内存,最新版本在http://www.linkdata.se/sourcecode.html可以获取

2. 使用
       memwatch不需要安装,只要下载包解压即可,有用的文件只有memwatch.c&memwatch.h,把这两个文件放入要检测的程序的文件夹中即可。编译的命令为:gcc -DMEMWATCH -DMW_STDIO test.c memwatch.c -o test

3. 实例
    编写如下代码
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <memwatch.h>
    int main() {
        char *hello;

        setenv("MALLOC_TRACE", "output", 1);
        mtrace();
        if ((hello = (char *) malloc(sizeof(char))) == NULL) {
            perror("Cannot allocate memory.");
            return -1;
        }

        return 0;
    }

    编译:gcc -DMEMWATCH -DMW_STDIO test.c memwatch.c -o test

4. 运行结果
   

memwatch.log的內容如下:

============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh =============

Started at Sat Jun 26 22:48:47 2004

Modes: __STDC__ 32-bit mwDWORD==(unsigned long)
mwROUNDALLOC==4 sizeof(mwData)==32 mwDataSize==32


Stopped at Sat Jun 26 22:48:47 2004

unfreed: <1> test.c(9), 1 bytes at 0x805108c     {FE .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .}

Memory usage statistics (global):
N)umber of allocations made: 1
L)argest memory usage       : 1
T)otal of all alloc() calls: 1
U)nfreed bytes totals       : 1
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JProfiler 是一款功能强大的 Java 应用程序性能分析工具,可以用于查找内存泄漏问题。下面是使用 JProfiler 查找内存泄漏问题的步骤: 1. 启动应用程序并将其与 JProfiler 连接。在 JProfiler 中,选择 "Session" -> "New Session" -> "Attach to a running JVM",然后选择要连接的应用程序和相应的 JVM。 2. 在 JProfiler 的 "Control Center" 窗口中选择 "Memory" 选项卡,并选择 "Recording Settings" 子选项卡。在这里,您可以设置内存分析的一些参数,例如记录时长、对象数量等。 3. 开始记录内存使用情况。单击 "Start Recording" 按钮,JProfiler 将开始记录内存使用情况。 4. 执行一些操作,以便应用程序尽可能多地使用内存。例如,执行一些繁重的操作或操作大量数据的任务。 5. 停止内存记录并分析结果。在 "Memory" 选项卡中,选择 "Heap Walker" 子选项卡。这将打开一个新窗口,显示应用程序中的对象。 6. 使用 "Show Dominator Tree" 按钮查看内存使用情况最高的对象。该按钮位于 "Heap Walker" 窗口的工具栏中。这将显示占用内存最多的对象及其相关引用。 7. 识别内存泄漏。查找可能引起内存泄漏的对象,并分析其引用关系。通过查看该对象的引用链,您可以确定是否存在任何对象持有了不必要的引用,导致这些对象不能被垃圾回收。 8. 通过修复代码中的问题来解决内存泄漏。找到代码中存在的问题,例如未正确释放对象或持有不必要的引用,并进行修复。 总之,使用 JProfiler 可以帮助您快速有效地识别内存泄漏问题并解决它们,从而提高应用程序的性能和稳定性。 ### 回答2: JProfiler是一种强大的Java性能分析工具,可以帮助定位和解决内存泄漏问题。下面是使用JProfiler来查找内存泄漏问题的步骤: 1. 启动目标应用程序和JProfiler。 2. 在JProfiler中选择“内存”选项卡。这将显示当前应用程序的内存使用情况。 3. 监控应用程序的内存使用情况,特别关注内存增长趋势。如果你发现内存占用总是增加而没有被释放,那么可能存在内存泄漏。 4. 在JProfiler中选择“快照”选项卡,然后点击“操作”按钮旁边的相机图标。这将创建一个内存快照,用于后续分析。 5. 在“快照”选项卡中选择“直方图”。这将显示应用程序中各个对象类型的内存使用情况。 6. 搜索大量占用内存的对象,特别是那些没有被及时释放的对象。通过查看对象的引用链,可以判断是否存在内存泄漏的可能。 7. 确定潜在的内存泄漏点后,可以使用JProfiler提供的其他功能进行进一步的内存泄漏分析。比如,可以使用线程分析来确定是否存在线程泄漏,使用内存分配跟踪来查找内存分配过程中的问题等。 8. 根据分析结果制定相应的解决方案,修复内存泄漏问题并重新测试应用程序。 9. 重复进行上述步骤,直到解决所有内存泄漏问题。 总的来说,使用JProfiler可以通过监控和分析内存使用情况,找出内存泄漏的根本原因,并提供相应的解决方案。它是一个非常有用的工具,可以提升应用程序的性能和稳定性。 ### 回答3: JProfiler是一款功能强大的Java性能分析工具,可以帮助我们定位和解决内存泄露的问题。 首先,使用JProfiler进行内存泄露的分析,我们可以通过以下几个步骤来进行操作。 第一步,打开JProfiler工具,并连接到我们想要分析的Java应用程序。 第二步,选择“内存”标签,进入内存分析界面。 第三步,开始记录内存数据。点击左上角的“开始记录内存数据”按钮,工具会开始记录内存使用情况。 第四步,进行快照分析。我们可以手动触发内存快照,或者选择自动快照。在快照分析界面,可以找到堆中存在的对象,并对其进行分析。 第五步,查找内存泄露的原因。我们可以通过查看对象的引用路径,找出哪些对象存在内存泄露。JProfiler会显示对象的引用关系,我们可以根据这些信息来定位内存泄露的问题。 第六步,确定内存泄露的根源,并解决问题。通过分析对象的引用路径,我们可以找到导致内存泄露的具体原因。然后,我们可以根据问题的性质采取相应的解决方法,比如释放无用的对象引用,或者进行垃圾回收优化等。 最后,我们可以使用JProfiler的监控功能,实时查看内存的使用情况,以及进行性能优化。通过不断的分析和优化,可以有效地解决内存泄露问题,提升应用程序的性能和稳定性。 总结来说,使用JProfiler可以帮助我们快速定位和解决内存泄露的问题,提高应用程序的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值