游戏中内存泄漏的查找

     我们的这款游戏从开发到上线至今已有大概4年了,昨天发现代码中有new出来的对象没有delete,程序退出后VS输出栏中居然没有提示,难道程序中没有内存泄漏检察?进一步的求证确定了我的担忧(我是半路进的项目组)。在代码中加上_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF)后,VS的输出栏赫然显示了大量的内存泄漏。在动手解决内存泄漏之前,先复习一下有关new操作符重载的相关知识:

new 操作符按其可见性可分为全局的与局部的(类成员),我们可以对他们进行重载,下面是VS 2010中new.cpp中new操作符的声明

1 void * operator new( size_t size );     //1
2 void * operator new ( size_t size, int nBlockUse, const char * szFileName, int nLine ); //2


void main()
{
   
char * p = new char;    //调用第1个new
   p = new ( _NORMAL_BLOCK, __FILE__, __LINE__ ) char;  //调用第2个new
}

调用new时,传入的参数比new声明时的参数少了一个,即第一个参数,该参数是new的对象的大小,由编译器填写,禁止程序员自己插手。

 

对一个类重载new和delete

class Student
{
    
void * operator new( size_t size )  //3
    {
         std::cout 
<< __FUNCTION__ << std::endl;
         
return malloc( sizeof(Student) );
    }
};
Student * pS = new Student();    //调用Student类内部的new,即第3个new

 

当我们new一个自定义类时,如果该类重载了new操作符,则优先使用该类内部定义的new,如果这时非要调用全局的new操作符怎么办呢?可以在new前面加两个冒号:

pS = ::new Student();  //调用全局的new,第1个new

 

下面回到解决内存泄漏的步骤上:

1 在程序必定会执行的路径上加上:

_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

不一定非得是程序的最开始处

2 使用上面给出的第2个new操作符,当程序退出时,它会在VS输出栏中注明是哪行代码引起的内存泄漏。即所有的new 都改为

new ( _NORMAL_BLOCK, __FILE__, __LINE__ )

 

完了。。。。。这样就可以了。

但是,我们程序已有的代码都写的是new,而不是new ( _NORMAL_BLOCK, __FILE__, __LINE__ )。


MFC中的解决方法:

#define new  new ( _NORMAL_BLOCK, __FILE__, __LINE__ )

这样好像是可以解决问题,但是我们游戏中用了Gamebryo游戏引擎,这个引擎中很多类内部重载了new操作符,并且还有如下的宏定义:

#define NiNew new( NI_MEMHINT_NONE, __FILE__, __LINE__ , __FUNCTION__ )

并且引擎自带的对象都是通过NiNew来创建的,如 NiNew NiAlphaProperty();

如果我们把new 宏定义成了new ( _NORMAL_BLOCK, __FILE__, __LINE__ ),那么碰到NiNew NiAlphaProperty()后,代码就被展开成为

new ( _NORMAL_BLOCK, __FILE__, __LINE__ )  ( NI_MEMHINT_NONE, __FILE__, __LINE__ , __FUNCTION__ ) NiAlphaProperty(); 当编译器尝试着用此代码与NiAlphaProperty类内部定义的new操作符去匹配时就抓瞎了,只能报错。

目前就只能自己再定义一个宏:

#define New   ::new ( _NORMAL_BLOCK, __FILE__, __LINE__ )

将代码中所有的new替换成New。

另一种内存泄漏检测方法就是借用第3方的库:
Visual Leak Detector 是一个不错的泄漏检测库,下载地址:
http://vld.codeplex.com/releases/view/82311
只需要在自己的程序的main函数所在的文件中#include <vld.h>就可以了,使用起来很方便。

(注: _CrtSetBreakAlloc()对大型的C++工程不太实用 )

posted on 2013-01-19 16:04 永遇乐 阅读(2838) 评论(4)  编辑 收藏 引用 所属分类: C & C++

评论

# re: 游戏中内存泄漏的查找 2013-01-19 19:32 eryar

好像有内存new出来后未释放,可以通过开源的小工具检查出来。。。  回复  更多评论   

# re: 游戏中内存泄漏的查找[未登录] 2013-01-22 08:37 alex

好像可以重载全局的new delete,在他们的实现里头,记录内存分配与释放时间、地址、地点、语句。内部调用原来的new delete实现。这样,运行结束时,查看下内存分配的链表啥的,就可以知道哪些地方的内存没有释放了。  回复  更多评论   

# re: 游戏中内存泄漏的查找 2013-01-28 15:05 wallwind

@alex
赞同。  回复  更多评论   

# re: 游戏中内存泄漏的查找 2013-02-02 09:48 边城浪

这个宏很实用.受教了.  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2012年8月>
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(6)

随笔分类

推荐Blog

友情链接

搜索

最新评论

阅读排行榜