zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    如何用js判断一个对象是不是Array
    js实现数组去重怎么实现?
    点击一个ul的五个li元素,分别弹出他们的序号,怎么做?
    盒子模型
    13. 查看网络端口、配置网络
    12. 查看系统硬件配置
    11. 系统状态管理
    9. iptables 配置
    10. 编译软件包
    8. 管理软件包
  • 原文地址:https://www.cnblogs.com/LittleHann/p/4353145.html
Copyright © 2011-2022 走看看