Linux C/C++ Memory Leak Detection Tool

目录

1. 内存使用情况分析
2. 内存泄漏(memory leak)
3. Valgrind使用

1. 内存使用情况分析

0x1: 系统总内存的分析

可以从proc目录下的meminfo文件了解到当前系统内存的使用情况汇总,其中
可用的物理内存 = memfree + buffers + cached
当memfree不够时,内核会通过回写机制(pdflush线程)把cached和buffered内存回写到后备存储器,从而释放相关内存供进程使用,或者通过手动方式显式释放cache内存:
echo 3 > /proc/sys/vm/drop_caches

$cat /proc/meminfo
MemTotal:        8388608 kB
MemFree:         6880760 kB
Buffers:               0 kB
Cached:          1490828 kB
SwapCached:            0 kB
Active:          1224960 kB
Inactive:         282832 kB
Active(anon):      17028 kB
Inactive(anon):      348 kB
Active(file):    1207932 kB
Inactive(file):   282484 kB
Unevictable:           0 kB
Mlocked:            4884 kB
SwapTotal:       1999864 kB
SwapFree:        1999864 kB
Dirty:               596 kB
Writeback:             0 kB
AnonPages:        202420 kB
Mapped:            37400 kB
Shmem:              4736 kB
Slab:            1937380 kB
SReclaimable:    1739632 kB
SUnreclaim:       197748 kB
KernelStack:       15920 kB
PageTables:        30188 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    51319712 kB
Committed_AS:   13594600 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      662532 kB
VmallocChunk:   34359070640 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:        4096 kB
DirectMap2M:     2076672 kB
DirectMap1G:    98566144 kB

0x2: 进程使用内存统计

在32位操作系统中,每个进程拥有4G的虚拟内存空间,其中0~3GB是每个进程的私有用户空间,这个空间对系统中其他进程是不可见的。3~4GB是linux内核空间,由系统所有的进程以及内核所共享的。通过访问/proc/{pid}/下相关文件,可以了解每个线程(进程)虚拟内存空间的使用情况,从而了解每个线程(进程)所消耗内存的多少

可以通过查看/proc/{pid}/maps文件来获取相关的虚拟地址空间内容

sudo cat /proc/1417/maps
2b4494635000-2b449463b000 r-xp 00000000 03:01 819306                     /sbin/klogd
2b449463b000-2b449463c000 rw-p 2b449463b000 00:00 0
2b449483b000-2b449483c000 rw-p 00006000 03:01 819306                     /sbin/klogd
2b449483c000-2b449483d000 rw-p 2b449483c000 00:00 0
2b449483d000-2b4494859000 r-xp 00000000 03:01 409674                     /lib64/ld-2.5.so
2b4494859000-2b449485b000 rw-p 2b4494859000 00:00 0
2b4494a59000-2b4494a5a000 r--p 0001c000 03:01 409674                     /lib64/ld-2.5.so
2b4494a5a000-2b4494a5b000 rw-p 0001d000 03:01 409674                     /lib64/ld-2.5.so
2b4494a5b000-2b4494ba9000 r-xp 00000000 03:01 409683                     /lib64/libc-2.5.so
2b4494ba9000-2b4494da9000 ---p 0014e000 03:01 409683                     /lib64/libc-2.5.so
2b4494da9000-2b4494dad000 r--p 0014e000 03:01 409683                     /lib64/libc-2.5.so
2b4494dad000-2b4494dae000 rw-p 00152000 03:01 409683                     /lib64/libc-2.5.so
2b4494dae000-2b4494db4000 rw-p 2b4494dae000 00:00 0
2b44adeca000-2b44adeeb000 rw-p 2b44adeca000 00:00 0                      [heap]
7fff58134000-7fff58149000 rw-p 7ffffffe9000 00:00 0                      [stack]
7fff58162000-7fff58165000 r-xp 7fff58162000 00:00 0                      [vdso]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0                  [vsyscall]

当进程申请内存时,实际上是glibc中内置的内存管理器接收了该请求,随着进程申请内存的增加,内存管理器会通过系统调用陷入内核,从而为进程分配更多的内存
针对堆段的管理,内核提供了两个系统调用brk和mmap,brk用于更改堆顶地址,而mmap则为进程分配一块虚拟地址空间
当进程向glibc申请内存时,如果申请内存的数量大于一个阀值的时候,glibc会采用mmap为进程分配一块虚拟地址空间,而不是采用brk来扩展堆顶的指针。缺省情况下,此阀值是128K,可以通过函数来修改此值
如果在实际的调试过程中,怀疑某处发生了内存泄露,可以查看该进程的maps表,看进程的堆段或者mmap段的虚拟地址空间是否持续增加,如果是,说明很可能发生了内存泄露,如果mmap段虚拟地址空间持续增加,还可以看到各个段的虚拟地址空间的大小,从而可以确定是申请了多大的内存,对调试内存泄露类问题可以起到很好的定位作用

Relevant Link:

http://os.51cto.com/art/201304/388070.htm

2. 内存泄漏(memory leak)

内存泄漏(memory leak),指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况
在编程时进行动态内存分配是非常必要的,它可以在程序运行的过程中帮助分配所需的内存,而不是在进程启动的时候就进行分配。然而有效地管理这些内存同样也是非常重要的
在大型的、复杂的应用程序中,内存泄漏是常见的问题,当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,那么对于该进程来说,会因此导致总可用内存的减少,这时就出现了内存泄漏

0x1: 内存泄漏的发生方式

1. 常发性内存泄漏
发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏 

2. 偶发性内存泄漏
发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要

3. 一次性内存泄漏
发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅有一块内存发生泄漏

4. 隐式内存泄漏
程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏

0x2: 常用内存泄漏检测工具

C/C++
1. Valgrind: Debugging and profiling Linux programs, aiming at programs written in C and C++
2. ccmalloc: Linux和Solaris下对C和C++程序的简单的使用内存泄漏和malloc调试库
3. LeakTracer: Linux、Solaris和HP-UX下跟踪和分析C++程序中的内存泄漏
4. Electric Fence: Linux分发版中由Bruce Perens编写的malloc()调试库
5. Leaky: Linux下检测内存泄漏的程序
6. Dmalloc: Debug Malloc Library
7. MEMWATCH: 由Johan Lindh编写,是一个开放源代码C语言内存错误检测工具,主要是通过gcc的precessor来进行
8. KCachegrind: A visualization tool for the profiling data generated by Cachegrind and Calltree 

Java
1. Memory Analyzer: 是一款开源的JAVA内存分析软件,查找内存泄漏,能容易找到大块内存并验证谁在一直占用它,它是基于Eclipse RCP(Rich Client Platform),可以下载RCP的独立版本或者Eclipse的插件
2. JProbe: 分析Java的内存泄漏
3. JProfiler: 一个全功能的Java剖析工具,专用于分析J2SE和J2EE应用程序。它把CPU、执行绪和内存的剖析组合在一个强大的应用中,GUI可以找到效能瓶颈、抓出内存泄漏、并解决执行绪的问题
4. JRockit: 用来诊断Java内存泄漏并指出根本原因,专门针对Intel平台并得到优化,能在Intel硬件上获得最高的性能
5. YourKit .NET & Java Profiling: 业界领先的Java和.NET程序性能分析工具
6. AutomatedQA: AutomatedQA的获奖产品performance profiling和memory debugging工具集的下一代替换产品,支持Microsoft, Borland, Intel, Compaq 和 GNU编译器。可以为.NET和Windows程序生成全面细致的报告,从而帮助您轻松隔离并排除代码中含有的性能问题和内存/资源泄露问题。支持.Net 1.0,1.1,2.0,3.0和Windows 32/64位应用程序
7. Compuware DevPartner Java Edition: 包含Java内存检测,代码覆盖率测试,代码性能测试,线程死锁,分布式应用等几大功能模块 

.NET
1. .NET Memory Profiler: 找到内存泄漏并优化内存使用针对C#,VB.Net,或其它.Net程序
2. Windows Leaks Detector: 探测任何Win32应用程序中的任何资源泄漏(内存,句柄等),基于Win API调用钩子
3. DTrace: 一款开源动态跟踪Dynamic Tracing,能在Unix类似平台运行,用户能够动态检测操作系统内核和用户进程,以更精确地掌握系统的资源使用状况,提高系统性能,减少支持成本,并进行有效的调节
4. IBM Rational PurifyPlus: 帮助开发人员查明C/C++、托管.NET、Java和VB6代码中的性能和可靠性错误。PurifyPlus 将内存错误和泄漏检测、应用程序性能描述、代码覆盖分析等功能组合在一个单一、完整的工具包中
5. Parasoft Insure++: 针对C/C++应用的运行时错误自动检测工具,它能够自动监测C/C++程序,发现其中存在着的内存破坏、内存泄漏、指针错误和I/O等错误。并通过使用一系列独特的技术(SCI技术和变异测试等),彻底的检查和测试我们的代码,精确定位错误的准确位置并给出详细的诊断信息。能作为Microsoft Visual C++的一个插件运行
6. Compuware DevPartner for Visual C++ BoundsChecker Suite: 为C++开发者设计的运行错误检测和调试工具软件。作为Microsoft Visual Studio和C++ 6.0的一个插件运行
7. Electric Software GlowCode: 包括内存泄漏检查,code profiler,函数调用跟踪等功能。给C++和.Net开发者提供完整的错误诊断,和运行时性能分析工具包 

FireFox / IE
1. Leak Monitor: 一个Firefox扩展,能找出跟Firefox相关的泄漏类型
2. IE Leak Detector (Drip/IE Sieve): Drip和IE Sieve leak detectors帮助网页开发员提升动态网页性能通过报告可避免的因为IE局限的内存泄漏。
3. JavaScript Memory Leak Detector: 微软全球产品开发欧洲团队(Global Product Development- Europe team, GPDE) 发布的一款调试工具,用来探测JavaScript代码中的内存泄漏,运行为IE系列的一个插件 

0x3: 内存检查原理

Memcheck检测内存问题的原理如下图所示

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

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

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

检测原理

1. 当要读写内存中某个字节时,首先检查这个字节对应的 A bit(Valid-Adress Map)。如果该A bit显示该位置是无效位置,memcheck 则报告读写错误
2. 内核(core)类似于一个虚拟的 CPU 环境,这样当内存中的某个字节被加载到真实的 CPU 中时,该字节对应的 V bit(Valid-Value Map) 也被加载到虚拟的 CPU 环境中。一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序输出,则 memcheck 会检查对应的V bits,如果该值尚未初始化,则会报告使用未初始化内存错误 

Relevant Link:

http://blog.csdn.net/ithomer/article/details/6928318
http://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/

3. Valgrind使用

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

Valgrind包括如下一些工具

1. Memcheck
这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分,Valgrind 中包含的 Memcheck 工具可以检查以下的程序错误
    1) 使用未初始化的内存 (Use of uninitialised memory)
      2) 使用已经释放了的内存 (Reading/writing memory after it has been free’d)
      3) 使用超过malloc分配的内存空间(Reading/writing off the end of malloc’d blocks)
      4) 对堆栈的非法访问 (Reading/writing inappropriate areas on the stack)
      5) 申请的空间是否有释放 (Memory leaks – where pointers to malloc’d blocks are lost forever)
      6) malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
      7) src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)
      8) 重复free

2. Callgrind
它主要用来检查程序中函数调用过程中出现的问题

3. Cachegrind
它主要用来检查程序中缓存使用出现的问题

4. Helgrind
它主要用来检查多线程程序中出现的竞争问题

5. Massif
它主要用来检查程序中堆栈使用中出现的问题

6. Extension
可以利用core提供的功能,自己编写特定的内存调试工具 

0x1: 编译安装

wget http://valgrind.org/downloads/valgrind-3.4.1.tar.bz2
tar xvf valgrind-3.4.1.tar.bz2
cd valgrind-3.4.1/
./configure --prefix/home/zhenghan.zh/valgrind
make
make install

0x2: 检测使用

为了使valgrind发现的错误更精确,如能够定位到源代码行,建议在编译时加上-g参数,编译优化选项请选择O0,虽然这会降低程序的执行效率

#include <stdlib.h>

void fun()
{
    int *p = (int*)malloc(10 * sizeof(int));
    //内存越界写入
    p[10] = 0;
}

int main(int argc, char* argv[])
{
    fun();
    return 0;
}

//gcc –g –O0 sample.c –o sample

运行valgrind

/home/zhenghan.zh/valgrind/bin/valgrind --tool=memcheck --leak-check=full /home/zhenghan.zh/memcheck/sample
/home/zhenghan.zh/valgrind/bin/valgrind /home/zhenghan.zh/memcheck/sample

Relevant Link:

http://zyan.cc/post/419/
http://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/

Copyright (c) 2014 LittleHann All rights reserved

时间: 2024-08-07 14:34:23

Linux C/C++ Memory Leak Detection Tool的相关文章

Memory Leak Detection in Embedded Systems

One of the problems with developing embedded systems is the detection of memory leaks; I've found three tools that are useful for this. These tools are used to detect application program errors, not kernel memory leaks. Two of these tools (mtrace and

Memory Leak Detection in C++

原文链接:http://www.linuxjournal.com/article/6556?page=0,0 An earlier article [“Memory Leak Detection in Embedded Systems”, LJ, September 2002, available atwww.linuxjournal.com/article/6059] discussed the detection of memory leaks when using C as the pro

内存泄漏(memory leak)和内存溢出

1. 什么是内存泄漏(memory leak)? 指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费. 2. 两种类型的内存泄漏: 堆内存泄漏(Heap leak).对内存指的是程序运行中根据需要分配通过malloc,realloc new等从堆中分配的一块内存,再是完成后必须通过调用对应的 free或者delete 删掉.如果程序的设计的错误导致这部分内存没有被释放,

Android 内存管理 &amp;Memory Leak &amp; OOM 分析

1.Android 进程管理&内存 Android主要应用在嵌入式设备当中,而嵌入式设备由于一些众所周知的条件限制,通常都不会有很高的配置,特别是内存是比较有限的.如果我们编写的代 码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至是死机.为了能够使得Android应用程序安全且快速的运行,Android 的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程演变过来的,也就是说每个应用程序都是在属于自己的进程中运行的.一方面,如果程序在运行

Memory Leak(内存泄漏)问题总结(转)

最近听了一些关于Memory Leak(内存泄漏)的seminar,感觉有些收获,所以留个记录,并share给朋友. 1 什么是Memory Leak. Memory Leak是指由于错误或不完备的代码造成一些声明的对象实例长期占有内存空间,不能回收.Memory Leak会造成系统性能下降,或造成系统错误. 2 Memory存储模式 我们通常写的C++或Java Code在内存里边的存储状况概如下图. 简单的说,一般局部变量存储于Stack中,以提高运行问速度.而New出来的变量则将引用信息或

大神的---解决tomcat内存溢出问题----tomcat报错:This is very likely to create a memory leak问题解决

tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因  在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样. 这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种情况:  1.OutOfMemoryError: Java heap space  2.OutOfMemoryError: PermGen space  3.OutOfMemoryError: unab

内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别

内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别 内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态. 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,就是溢出. 要点: 一.内存泄露是指程序中间动态分配了内存,但在程序结束时没有释放这部分内存,从而造成那部分内存不可用的情况,重启计算机可以解决,但也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件

Tomcat出现To prevent a memory leak, the JDBC Driver has been forcibly unregistered.问题的一种情况记录

问题出现背景: 最近重构了一个老的项目,这个项目中间曾经参与维护的人比较多,代码非常乱,所以对其进行了一次小的重构和升级,将系统环境从JDK1.6+Tomcat6+WindowsServer升级JDK1.8+Tomcat8+Linux,但是重构完成的时候出现了错误,Tomcat一直无法启动. 错误信息 To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 这个错误: 参考的资料 参考了stack ove

tomcat报错:This is very likely to create a memory leak问题解决

tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因  在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样.  这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种情况:  1.OutOfMemoryError: Java heap space  2.OutOfMemoryError: PermGen space  3.OutOfMemoryError: una