转载来源: http://www.blogjava.net/wangle/archive/2007/06/17/124813.html
另外也推荐看一下该博主的另一篇:(Ogre中的多窗口渲染方法) http://www.blogjava.net/wangle/archive/2007/06/16/124696.html
刚开始使用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库,呵呵。