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 ...
随机推荐
- java常用组件
一.Jpanel 1.面板:容器类组件 2.用途:与Layout配合使用,JFrame—>JPanel—>Layout 二.JTextField 1.文本框 2.JPasswordFiel ...
- javaScript 时间转换,将后台返回的时间为一串数字转成正常格式
js完整代码: function transferTime(cTime){ var jsonDate = new Date(parseInt(cTime)); Date.prototype.forma ...
- 查询和设置mysql事务隔离级别
1.查看当前会话隔离级别 select @@tx_isolation; 2.查看系统当前隔离级别 select @@global.tx_isolation; 3.设置当前会话隔离级别 set sess ...
- linux几种常见的文件内容查找和替换命令
作为一个以前没怎么接触过linux的小白,开始使用linux,各种不习惯,这周遇到一个文件内容测查找和替换的需求.学习了以下几种实现方式: 1.vi命令下的查找和替换 1.1 vi下的查找 /patt ...
- SQL SERVER 内存
http://www.cnblogs.com/CareySon/archive/2012/08/16/HowSQLServerManageMemory.html
- spring事务详细理解
数据并发的问题 一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库.数据库中的相同数据可能同时被多个事务访问,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性.这些 ...
- 【jar】JDK将单个的java文件打包为jar包,并引用到项目中使用【MD5加密】
==================================================================================================== ...
- 如何手写一款SQL injection tool?
0×01 前言 我想在FreeBuf上出没的人一般都是安全行业的,或者说是安全方面的爱好者,所以大家对sql注入应该都比较了解,反正我刚入门的时候就是学的这些:sql注入.xss之类的.sql注入从出 ...
- Basic Vim Configuration
原文: https://computers.tutsplus.com/tutorials/basic-vim-configuration--cms-21498 原来,vim的配置文件,.vimrc也是 ...
- Cocos2d-X中的粒子
Cocos2d-x引擎提供了强大的type=cocos2d-x&url=/doc/cocos-docs-master/manual/framework/native/v3/particle-s ...