简单的Memory leak跟踪(一) DEBUG_NEW方案
来源:互联网 发布:淘宝差评怎么删除不了 编辑:程序博客网 时间:2024/05/17 23:38
前言
C++编码中Memory Leak是一个很讨厌却又挥之不去的话题,最近由于引入了GC,为了验证GC是否确实正常free了内存,于是先提供了一个内存分配的Tracer。
与分配器不同,分配器主要解决的是两个问题:
1、性能,池式分配往往能提供比直接Virtual Allocation快得多的效能。据说这一原则在Vista后无效了,因为微软修改了VA的实现机制,只是听说,没有实际测试过。
2、碎片,避免大量散内存分配冲散了本身连续的内存,导致后面内存因为没有连续区块而分配不出来。
我们的跟踪器Tracer主要是想解决一个问题,就是啥时候分了内存,啥时候删的,程序退出时删除掉没。
方案一:DEBUG_NEW方案
基本上,这个主题之前也有很多前辈都写过了,这里也没有超越前辈们的什么方案,只是自己做这个模块时的心得和理解。
这个问题有两个比较成型的方案,一个就是MFC的DEBUG_NEW方案,MAX SDK用的也是这个方案。
其实原理很简单,我们只要能获取到当前语句的文件名和行号,然后new的时候,我们让我们的Tracer记录一下当前的地址,并与文件名和行号绑定,然后,delete的时候,按照地址来去掉这条记录即可。
实现起来如何实现呢?
这个问题无非是要解决两个问题,首先,new这个东西,我们需要接管下来,接管下来后才能记录我们自己的信息。
C++的operator new是可以有不同形式的重载的,比如:
void* operator new (size_tInSize, const char* InLogMsg){ std::cout << InLogMsg <<std::endl; return ::malloc(InSize);}
调用这个重载时,new就要这么调了:
int* p = new ("我正在分配内存") int;
注意,new和operator new不是一回事儿,而提供了特殊形式的operator new后,需要相应地提供类似的operator delete,否则会有Level 1 warning。
对这个问题有兴趣可见本文最后的补充1,它与本文的主题无关,暂时无视。
第二个问题是,我们如何获知当前语句的文件和航好呢?
C++可以用下面的方法来取得当前语句所在的文件和行号:
std::cout << "当前文件为:" <<__FILE__ <<"。当前行号为:" << __LINE__<<std::endl;
准备工作齐活儿了,准备开始吧!
首先,我们需要提供一个Tracer来记录文件名和行号这些信息:
class TracerFileLn{public: TracerFileLn& singleton();private: struct _AllocInfo { const char*filename_; size_tfileLn_; }; typedefstd::hash_map<qword, _AllocInfo>alloc_hash; alloc_hashallocInfoHash_;public: void traceMalloc(void* InPtr, const char* InFilename, size_t InFileLn) { _AllocInfosAllocInfo = { InFilename, InFileLn }; allocInfoHash_.insert( alloc_hash::pair((qword)InPtr, sAllocInfo) ); } void traceFree(void* InPtr) { auto it = allocInfoHash_.find(InPtr); allocInfoHash_.erase(it); }};
所以,我们能不能提供下面这个new的重载呢?
void* operator new(size_tInSize,const char* InFilename,size_t InFileLn)
然后,operator new这么实现:
void* operator new(size_t InSize, const char* InFilename, size_t InFileLn){ void* pPtr = ::malloc(InSize); TracerFileLn::singleton().traceMalloc(pPtr, InFilename, InFileLn); return pPtr;}
然后,operator delete需要这么实现:
void operator delete(void* InPtr){ TracerFileLn::singleton().traceFree(InPtr);}void operator delete(void* InPtr, const char* InFilename,size_t InFileLn){ TracerFileLn::singleton().traceFree(InPtr);}
记得 new[] 和 delete[] 也要做相应的实现。
但这样的话,咱们就不能再使用C++的原生new了,而是必须要用新的new。
int * pPtr = new(__FILE__,__LINE__)int;
所有使用new的地方都要这么写,太麻烦了?不过这难不倒我们,有宏呢,就跟MFC DEBUG_NEW那样:
#define DEBUG_NEW new (__FILE__,__LINE__)
#define new DEBUG_NEW
然后再用new 的地方实际上就会被替换为new (__FILE__,__LINE__) 了。
int * pPtr = newint;
继续这么写就可以,只是在这句话之前,必须要确保其前面有#define new DEBUG_NEW的宏声明。
信息Trace下来了,程序结束后,只需要看hash里还有哪些AllocInfo,一个个Dump出来就可以查到相应的内存泄露了。
看起来很方便吧?方不方便,后面还会继续展开,敬请期待。
补充1:
- 简单的Memory leak跟踪(一) DEBUG_NEW方案
- 简单的Memory leak跟踪(三) 方案2:Dbghelp
- 简单的Memory leak跟踪
- 简单的Memory leak跟踪(二)不想Tracer的场合
- 简单的Memory leak跟踪(四)参考代码、组织和几个问题的讨论
- 烦人的memory leak
- Java的Memory leak
- Pthread导致的memory leak
- 内存泄漏(memory leak)
- Android内存监控与分析(一):内存泄漏(Memory Leak)与内存溢出(OOM)的表现
- Memory Leak
- memory leak
- Memory leak
- Java内存泄露(Memory Overflow)和内存泄露(Memory Leak)的区别
- Visual leak detector 的使用(一)
- 折腾了一星期的memory leak
- 解决了困扰多日的Memory Leak
- [转] 解决 iphone的 memory leak 问题
- winlogon源码分析
- 三大框架建立Web项目,所需jar包和各个jar包
- 归档Redis在Windows,linux平台下的安装配置
- oracle 11g导出空表处理
- javaIO之Properties:读取*.properties配置文件
- 简单的Memory leak跟踪(一) DEBUG_NEW方案
- 转载并记录一遍关于骨骼动画的cocos2d论坛帖子。
- Struts2的属性驱动与模型驱动的区别
- ubuntu下移植ffmpeg到android
- 管理要像一部好电影
- WIZ610wi用户手册-版本 1.9.1(二)
- vc 创建桌面快捷方式
- 浅析C#中new、override、virtual关键字的区别
- <剑指offer>之链表题目