Ogre與MFC結合時的內存泄漏問題

轉載自: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)”

 

發佈了95 篇原創文章 · 獲贊 34 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章