c/c++通用内存泄漏检测框架GMFD(General Memory Fault Detection Framework)
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)的更多相关文章
- 为什么各大厂自研的内存泄漏检测框架都要参考 LeakCanary?因为它是真强啊!
请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...
- 【转】简单内存泄漏检测方法 解决 Detected memory leaks! 问题
我的环境是: XP SP2 . VS2003 最近在一个项目中,程序退出后都出现内存泄漏: Detected memory leaks! Dumping objects -> {98500} n ...
- 【Visual Studio】简单内存泄漏检测方法 解决 Detected memory leaks! 问题(转)
原文转自 http://blog.csdn.net/u011430225/article/details/47840647 我的环境是: XP SP2.VS2003 最近在一个项目中, 程序退出后都出 ...
- Android 内存泄漏检测工具 LeakCanary(Kotlin版)的实现原理
LeakCanary 是一个简单方便的内存泄漏检测框架,做 android 的同学基本都收到过 LeakCanary 检测出来的内存泄漏.目前 LeakCanary 最新版本为 2.7 版本,并且采用 ...
- Android 性能优化之内存泄漏检测以及内存优化(中)
https://blog.csdn.net/self_study/article/details/66969064 上篇博客我们写到了 Java/Android 内存的分配以及相关 GC 的详细分析, ...
- android 内存泄漏检测工具 LeakCanary 泄漏金丝雀
韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com 内存泄漏检测工具 android 内存泄漏检测工具 ======== 内存泄漏 就是 无用的对 ...
- 【转】Unix下C程序内存泄漏检测工具Valgrind安装与使用
Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Goo ...
- C++程序内存泄漏检测方法
一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...
- 利用Android Studio、MAT对Android进行内存泄漏检测
利用Android Studio.MAT对Android进行内存泄漏检测 Android开发中难免会遇到各种内存泄漏,如果不及时发现处理,会导致出现内存越用越大,可能会因为内存泄漏导致出现各种奇怪的c ...
随机推荐
- layDate 日期与时间组件 入门
首先第一步 在官方下载layDate文件.layUI官网:http://layer.layui.com/ https://www.layui.com/laydate/ layDate文件的下载步 ...
- MySQL中limit使用动态参数的解决方法(拼接SQL字符串语句来执行SQL)
官方好像说过limit已经在5.6版本上支持了动态参数,但是测试时依然还是不行. 那么要解决limit动态参数唯一能做的就是使用字符串SQL拼接的形式,然后再进行执行. 一般有以下方式解决: 1.存储 ...
- Java出现错误“Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )”的问题分析
若出现:Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )这样的问题,一般是转义字符的问题,下 ...
- 邁向IT專家成功之路的三十則鐵律 鐵律七:IT人效率之道-時間管理
彷間有許多與時間管理方面的相關書籍與實務課程,但是究竟對於一位IT專業人士來說,甚麼樣的時間管理法則才是最有效率的呢?過去有許多IT朋友私下請教顧大俠這個問題,而顧大俠始終沒有很完整的分享這方面的經驗 ...
- 8.【nuxt起步】-vue组件之间数据交互
那么现在问题来了,我现在是在index.vue获取了服务端的数据,怎么传值到maincontent.vue?当然你也可以把获取数据放在maincontent.vue,但假如有些数据同时在header, ...
- 高通msm8994启动流程简单介绍
处理器信息 8994包括例如以下子系统: 子系统 处理器 含义 APSS 4*Cortex-A53 应用子系统 APSS 4*Cortex-A57 应用子系统 LPASS QDSP6 v5.5A(He ...
- python matplotlib imshow热图坐标替换/映射
今天遇到了这样一个问题,使用matplotlib绘制热图数组中横纵坐标自然是图片的像素排列顺序, 但是这样带来的问题就是画出来的x,y轴中坐标点的数据任然是x,y在数组中的下标, 实际中我们可能期望坐 ...
- 使用canvas 的api 实现 图片的显示 及 压缩
在移动端压缩图片并且上传主要用到filereader.canvas 以及 formdata 这三个h5的api.逻辑并不难.整个过程就是: (1)用户使用input file上传图片的时候,用file ...
- python--多种程序分析(2)
1.文件操作有哪些模式?请简述各模式的作用 r模式只读 w模式只写 a模式只添加 r+可读可写 w+可写可读 a+可读可添加 rb 二进制只读 wb 二进制只写 ab 二进制添加 ...
- 错误 1 error C1083: 无法打开包括文件: “numpy/arrayobject.h”: No such file
问题:错误 1 error C1083: 无法打开包括文件: “numpy/arrayobject.h”: No such file 解答:加入include路径:E:\env\Anaconda2x6 ...