Ogre中的内存泄露
刚开始使用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库,呵呵。
转自http://www.blogjava.net/wangle/archive/2008/11/18/124813.html
今天在看OGRE中的sample时,发现在createScene中的用new创建的的灯光、节点、实体,都没找到相应的delete,因此上网查找了关于OGRE内存回收的方法,看了上面这篇文章,发现应该是在 Root析构函数中,将场景中的由Ogre::Root,Ogre::SceneManager创建的对象都delete掉了,我已通过单步跟踪证实。
上述的内存泄漏问题的两种解决方法我都试了,OGRE1.6中第二种解决办法已经不行,因为OGRE中的宏定义变了,已经变为三种内存管理方式
#define OGRE_MEMORY_ALLOCATOR_STD 1
#define OGRE_MEMORY_ALLOCATOR_NED 2
#define OGRE_MEMORY_ALLOCATOR_USER 3
并且在代码中直接定义#define OGRE_MEMORY_ALLOCATOR OGRE_MEMORY_ALLOCATOR_STD
都没有编译开关让我们选择
所以现在具体怎么改还不清楚
另外第一种解决方法有个问题,如果你的工程支持UNICODE,那么会报错:
1>msvcrtd.lib(crtexew.obj) : error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数 ___tmainCRTStartup 中被引用
选择使用多字节字符集就不会报错...
一些说明:
CrtDumpMemoryLeaks()就是显示当前的内存泄漏。
注意是“当前”,也就是说当它执行时, 所有未销毁的对象均会报内存泄漏。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/geeeeeeee/archive/2008/12/05/3456281.aspx