Ogre与MFC结合时的内存泄漏问题

来源:互联网 发布:体彩网络销售平台 编辑:程序博客网 时间:2024/04/28 22:03

转载自:http://hi.baidu.com/monboy/item/5e06ccefaa50a80c65db0091

刚开始使用Ogre时总是碰到内存泄露,而且往往是一泄千里,等半分钟才能打完日志,我想这和Ogre中的大量大对象很有关系。下面就来分析一下内存泄露的产生原因。

1. MFC中使用Ogre时发生的内存泄露

这个问题比较有意思,其实并没有发生泄露,而是MFC自作主张的认为发生了内存泄露,实际上内存并不是没有释放,而是在VC报内存泄露之后释放,先来看一看MFC报内存泄露时的调用堆栈:

msvcr71d.dll!_CrtDumpMemoryLeaks() 行2208 C
mfc71d.dll!_AFX_DEBUG_STATE::~_AFX_DEBUG_STATE() 行127 C++
mfc71d.dll!_AFX_DEBUG_STATE::`scalar deleting destructor'() + 0xf C++
mfc71d.dll!CProcessLocalObject::~CProcessLocalObject() 行472 + 0x26 C++
mfc71d.dll!CProcessLocal<_AFX_DEBUG_STATE>::~CProcessLocal<_AFX_DEBUG_STATE>() + 0xf C++
mfc71d.dll!$E10() + 0xd C++
mfc71d.dll!_CRT_INIT(void * hDllHandle=0x7c140000, unsigned long dwReason=0, void * lpreserved=0x00000001) 行234 C
mfc71d.dll!_DllMainCRTStartup(void * hDllHandle=0x7c140000, unsigned long dwReason=0, void * lpreserved=0x00000001) 行288 + 0x11 C

 

AFX_DEBUG_STATE的析构函数:

_AFX_DEBUG_STATE::~_AFX_DEBUG_STATE()
{
#ifndef _AFX_NO_DEBUG_CRT
_CrtDumpMemoryLeaks();
int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(nOldState & ~_CRTDBG_LEAK_CHECK_DF);

_CrtSetReportHook(pfnOldCrtReportHook);
_CrtSetDumpClient(pfnOldCrtDumpClient);
#endif // _AFX_NO_DEBUG_CRT
}

很显然CrtDumpMemoryLeaks()是在mfc71d.dll卸载时被调用的,如果这个时候OgreMain_d.dll还没有卸载,那么在Ogre中new的全局变量也就还没有释放,所以MFC会认为产生了内存泄露。如何处理这样的问题呢。很简单,让OgreMain_d.dll在mfc71d.dll之前析构,但是默认的MFC程序似乎不是这样干的(为什么呢?),这就要求对项目设置作一点调整,使得Mfc71d.dll在OgreMian之前被链接,这样程序运行时MFC71d就会早于Ogre加载,也就晚于Ogre卸载。具体设置如下:

i) in the General tab, switch "Use MFC in a shared DLL" to "Use Standard Windows Libraries"
ii) in the C/C++/Preprocessor tab, add _AFXDLL to the preprocessor definitions
iii) in the Linker/Input tab, add mfc80d.lib anywhere before OgreMain_d.lib

另一种方法是,使用Ogre自己的MemoryManager,并且禁止调用MFC的DEBUG_NEW,这需要先

#define OGRE_DEBUG_MEMORY_MANAGER 1

然后删除cpp中的以下行

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

这样Ogre中会使用自己的new/delete,而不是调用vccrt中的_heap_alloc_debug

 

2. Ogre中的对象没有释放

由于Ogre中的很多对象并不是只要delete Root就可以释放的。最好所有的对象都不要自己new,而是通过Ogre::Root,Ogre::SceneManager等创建,这些对象在Root析构时会自己销毁,但是对于从Ogre类派生的类,由于Ogre不存在Create这些类的函数,所以只能在自己的代码中new产生,并由自己负责析构了,比如MovableObject派生的MovableText。当然Ogre也会给你一个将新对象加入其管理的接口,对于MovableText就必须再实现一个MovableTextFactory才行。总之要小心小心再小心。

最后抱怨一下Ogre太大了,有一个OgreLite就好了。现在这样使用起来光链接都要半天,真是太夸张了,所以没事最好不要修改Ogre库,呵呵。

 

 

第一步,是卸载dll先后顺序的问题,让OgreMain_d.dll在mfc80d.dll之前析构,老外早就有分析了:
 i) in the General tab, switch "Use MFC in a shared DLL" to "Use Standard Windows Libraries"
 ii) in the C/C++/Preprocessor tab, add _AFXDLL to the preprocessor definitions
 iii) in the Linker/Input tab, add mfc90ud.lib anywhere before OgreMain_d.lib
 
第二步,删除自己代码中的所有的#defin new DEBUG_NEW,然后在 CApp的构造函数中加入 AfxEnableMemoryTracking(FALSE);


机子本来不快,这样总不至于程序结束的时候慢死。。。自己写代码注意内存问题



出现错误:

1>Compiling...
1>stdafx.cpp
1>d:/program files/microsoft visual studio 9.0/vc/atlmfc/include/afxver_.h(81) : fatal error C1189: #error :  Please use the /MD switch for _AFXDLL builds

解决方法:
    c/c++ ---- Code Generation  --------- runtime library 改为 “Multi-threaded Debug DLL (/MDd)”

 

原创粉丝点击