http://qa.baidu.com/blog/?p=171

1 背景:

x86平台有完善的用户态检测内存工具比如valgrind等,可以监控程序运行中详细的内存信息,从而精确定位内存问题。然而随着新平台的快速诞生(比如Tilera的TilePro64 CPU),这些工具不能被及时地移植,导致新平台缺乏相应的手段来定位内存错误,如内存越界,泄漏等,而只能使用粗粒度的方法top,free 等指令观察进程的动态内存总额。其缺点是粒度太粗,而且内存的总数变化有很多原因引起,在复杂的系统里,很难精确定位内存问题的根源,甚至会漏报错报,这严重影响了新平台(如Tilera)开发与测试的效率。针对这个问题,我们提出了一个通用的新平台针对c/c++内存错误检测框架。
该框架可适用于任何平台。其通过重写标准库的内存分配和释放函数(如malloc, new, new[], free,delete,delete[]等), 以及维护一个全局的内存分配map数据结构实现。重写后的内存分配比如my_malloc首先调用系统malloc功能,然后记录每一次malloc执行过程中的内存操作信息(包括文件名、行号以及内存尺寸,函数调用栈),以指针值为 key值,存进维护的全局map表。而重写的my_free则是根据传入的指针值在 map 中查找相应的数据项并将之删除,而后调用系统的free 将指针所指向的内存块释放。这样当程序退出的时候,map 中的剩余的数据项就是我们期望检测的内存泄漏信息。我们可以输出泄漏内存块的详细日志,比如文件名,行号等等。这将大大提高类似Tilera平台的内存问题追查效率,提高开发和测试的速度和质量。

2 基本原理:
1)    通过重写非共享内存分配释放函数malloc, new, new[],free,delete,delete[]截获 它们在执行过程中的内存操作信息。重载形式如下:
void* malloc( size_t nSize, char* pszFileName, int nLineNum )
void* new( size_t nSize, char* pszFileName, int nLineNum )
void* operator new[]( size_t nSize, char* pszFileName, int nLineNum )
void free( void *ptr )
void delete( void *ptr )
void operator delete[]( void *ptr )

2)    通过重写共享内存分配释放函数mspace_malloc,mspace_free,重写形式如下:

void* my_mspace_malloc( mspace msp,unsigned int Size, char* pszFileName, int nLineNum )
void my_mspace_free(mspace msp, void *ptr )

3)    我们对malloc, new, new[],mspace_malloc进行了重载,参数包括size_t nSize、文件名和行号,这里的文件名和行号就是这次malloc, new, new[],mspace_malloc操作符被调用时所在的文件名和行号,这个信息将在发现内存泄漏时输出,以帮助定位泄漏具体位置。对于 free,delete,delete[],mspace_free参数为指针地址。

3 实例:
以My_malloc, My_free为例,重写函数结构如下:

1.    在重写的my_malloc函数版本中,我们将调用malloc 的原始版本并将相应的 size_t 参数传入,然后,我们将malloc的原始版本返回的指针值以及该次分配所在的文件名和行号信息记录下来,这里采用STL 的 map数据结构存储,以指针值为 key 值,文件名,行号等信息作为一个结构体是value值。
My_free重写函数结构如下:

2.    当my_free 被调用时,我们根据传入的指针值在 map 中找到相应的数据项并将之删除,而后调用 free 将指针所指向的内存块释放。这样当程序退出的时候,map 中的剩余的数据项就是我们企图检测的内存泄漏信息。

4 实现关键点:
1)    如何取得内存分配代码所在的文件名和行号?
利用 C 的预编译宏 __FILE__ 和 __LINE__,这两个宏将在编译时在指定位置展开为该文件的文件名和该行的行号

2)    利用宏定义开关决定走普通分支还是内存检测分支?
#if defined( MEM_DEBUG )
#define malloc DEBUG_MALLOC
#define free DEBUG_FREE
#endif

3)    何时创建用于存储内存数据的 map 数据结构,如何管理,何时打印内存泄漏信息?
设计一个类来封装这个 map 以及对它的插入删除操作,然后构造这个类的一个全局对象(appMemory),在全局对象(appMemory)的构造函数中创建并初始化这个数据结 构,而在其析构函数中对数据结构中剩余数据进行分析和输出。new 中将调用这个全局对象的 insert 接口将指针、文件名、行号、内存块大小等信息以指针值为 key 记录到 map 中,在delete 中调用 erase 接口将对应指针值的 map 中的数据项删除,同时对 map 的访问需要进行互斥同步,因为同一时间可能会有多个进程进行堆上的内存操作。

4)    如何为非共享内存申请map?如何为共享内存申请map?非共享内存的map,对于多进程则有多个map,可按(3)的方法处理。而对于共享内存,可能A进程申请到B进程才释放,但是每个进程一个map,我们去扫描这些每个map时就会出现误报的现象,因此需要采取将map放入共享内存方法:我们申请一块共享内存区域为map,这个map对各进程是共享的。当程序中各进程调用共享内存时,将各进程分配的指针及文件名行号等详细信息存进这共享的map。程序结束时,扫描该共享的map,就能得到未释放的信息。将 map放入共享内存使用c++标准库时需要我们自己实现一个基于共享内存的allocator,替换map默认的allocator,在这个allocator中实现map的内存分配方案。也可以使用boost库(1.35以上版本),它增加了一个叫做boost::interprocess的库,具体可参考http://blog.cong.co/stl-alloc.html

5)    如何使用该工具?
内存泄露检测框架提供接口libmemck.h,内容如下


在被测试程序里包含如下代码即可使用
 


6)    何时如何捕获信号,生成leak文件?

定义一个全局的类得对象,在该类得构造函数里通过signal函数捕获SIGINT、SIGABRT、SIGFPE、SIGTERM信号,当捕获到这些信号其中之一时,开始扫描map并将map剩余信息写入leak文件展示。

7)    对临界资源的控制?
共享内存的各进程共享的map,各进程间进行读写操作需要加锁,我们这里采用的是信号灯实现。
非共享内存各个进程对应的map,在各进程进行插入删除操作时也需要加锁实现

8)    程序中malloc作为函数指针?
由于将原型malloc(size)重写为my_malloc(size,__FILE__,__LINE__),这样由于函数类型不一致,导致程序调用该工具时编译无法通过,真对这种情况的解决办法为:重写malloc(size)为my_malloc_p(size)这样除了文件名和行号无法得知外,泄露的多少内存可以报出。

(作者:Wdan)

c/c++通用内存泄漏检测框架GMFD(General Memory Fault Detection Framework)的更多相关文章

  1. 为什么各大厂自研的内存泄漏检测框架都要参考 LeakCanary?因为它是真强啊!

    请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...

  2. 【转】简单内存泄漏检测方法 解决 Detected memory leaks! 问题

    我的环境是: XP SP2 . VS2003 最近在一个项目中,程序退出后都出现内存泄漏: Detected memory leaks! Dumping objects -> {98500} n ...

  3. 【Visual Studio】简单内存泄漏检测方法 解决 Detected memory leaks! 问题(转)

    原文转自 http://blog.csdn.net/u011430225/article/details/47840647 我的环境是: XP SP2.VS2003 最近在一个项目中, 程序退出后都出 ...

  4. Android 内存泄漏检测工具 LeakCanary(Kotlin版)的实现原理

    LeakCanary 是一个简单方便的内存泄漏检测框架,做 android 的同学基本都收到过 LeakCanary 检测出来的内存泄漏.目前 LeakCanary 最新版本为 2.7 版本,并且采用 ...

  5. Android 性能优化之内存泄漏检测以及内存优化(中)

    https://blog.csdn.net/self_study/article/details/66969064 上篇博客我们写到了 Java/Android 内存的分配以及相关 GC 的详细分析, ...

  6. android 内存泄漏检测工具 LeakCanary 泄漏金丝雀

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com 内存泄漏检测工具 android 内存泄漏检测工具 ======== 内存泄漏 就是  无用的对 ...

  7. 【转】Unix下C程序内存泄漏检测工具Valgrind安装与使用

    Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Goo ...

  8. C++程序内存泄漏检测方法

    一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...

  9. 利用Android Studio、MAT对Android进行内存泄漏检测

    利用Android Studio.MAT对Android进行内存泄漏检测 Android开发中难免会遇到各种内存泄漏,如果不及时发现处理,会导致出现内存越用越大,可能会因为内存泄漏导致出现各种奇怪的c ...

随机推荐

  1. 【APIO2015】Palembang Bridges

    题目描述 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 $A$ 和区域 $B$. 每一块区域沿着河岸都建了恰好 $1000000001$ 栋的建筑,每条岸边的建筑都从 $0$ 编号到 $100 ...

  2. electron入门教程

    1.atom/electron github: https://github.com/atom/electron 中文文档: https://github.com/atom/electron/tree ...

  3. 类加载器在加载类 的时候就已经对类的static代码块和static变量进行了初始化

    类装载器ClassLoader 类装载器工作机制 类装载器就是寻找类的节码文件并构造出类在JVM内部表示对象的组件.在Java中,类装载器把一个类装入JVM中,要经过以下步骤: [1.]装载:查找和导 ...

  4. DELPHI是怎么实现跨平台的?

    DELPHI是怎么实现跨平台的? 首先跨平台必须要兼容原来的语法,以线程的临界区对象为例: TCriticalSection = class(TSynchroObject){$IFDEF POSIX} ...

  5. Android图片缓存之Glide进阶(四)

    前言: 前面学习了Glide的简单使用(http://www.cnblogs.com/whoislcj/p/5558168.html),今天来学习一下Glide稍微复杂一点的使用. GlideModu ...

  6. Android View 绘制流程(Draw) 完全解析

    前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程.测量流程决定了View的大小,布局流程决定了View的位 ...

  7. Activiti 流程部署方式 activi 动态部署(高级源代码篇)

    Activiti的流程 部署方式有非常多种方式,我们能够依据activit工作流引擎提供的ap方式进行部署. 当然了实际需求决定你要使用哪一种api操作,后面的总结具体介绍了使用场景. 以下看一下部署 ...

  8. 【Todo】Java学习路线(方向指导)

    在网上搜了下Java学习路线(关键词:学习,因为众所周知,实践出牛人,在平时工作不怎么深入的情况下,才强调学习的方向的重要性 ^_^) 发现下面知乎这个回答写的真好.mark如下: https://w ...

  9. 基于ACIS/HOOPS的3D应用开发简介 【转】

    (整理) 平台:                造型引擎——ACIS         显示引擎——Direct3D/OpenGL/GDI         应用框架——HOOPS   组件关系图     ...

  10. Keras使用的一些细节

    1.Keras输出的loss,val这些值如何保存到文本中去: Keras中的fit函数会返回一个History对象,它的History.history属性会把之前的那些值全保存在里面,如果有验证集的 ...