一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

VC++內(nèi)存泄露定位

 9loong 2009-12-09
http://feikyo.cool.blog.163.com/blog/static/12206263820096223015272/

內(nèi)存泄漏定位

    今天調(diào)試程序,發(fā)現(xiàn)有內(nèi)存泄漏但是沒有提示具體是哪一行,搞得我很頭疼。結(jié)果在網(wǎng)上搜索了一些資料,經(jīng)自己實踐后整理如下:

 

    第一種:通過"OutPut窗口"定位引發(fā)內(nèi)存泄漏的代碼(下面轉(zhuǎn),我寫的沒原文好,也懶得寫)。

 我們知道,MFC程序如果檢測到存在內(nèi)存泄漏,退出程序的時候會在調(diào)試窗口提醒內(nèi)存泄漏。例如:

 

class CMyApp : public CWinApp
{
public:
   BOOL InitApplication()
   {
       int* leak = new int[10];
       return TRUE;
   }
}; 
產(chǎn)生的內(nèi)存泄漏報告大體如下:

 

Detected memory leaks!
Dumping objects ->
c:\work\test.cpp(186) : {52} normal block at 0x003C4410, 40 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete. 
這挺好。問題是,如果我們不喜歡MFC,那么難道就沒有辦法?或者自己做?

呵呵,這不需要。其實,MFC也沒有自己做。內(nèi)存泄漏檢測的工作是VC++的C運行庫做的。也就是說,只要你是VC++程序員,都可以很方便地檢測內(nèi)存泄漏。我們還是給個樣例:

 

#include <crtdbg.h>

inline void EnableMemLeakCheck()
{
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}

void main()
{
   EnableMemLeakCheck();
   int* leak = new int[10];

 運行(提醒:不要按Ctrl+F5,按F5),你將發(fā)現(xiàn),產(chǎn)生的內(nèi)存泄漏報告與MFC類似,但有細(xì)節(jié)不同,如下:

 

Detected memory leaks!
Dumping objects ->
{52} normal block at 0x003C4410, 40 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete. 
為什么呢?看下面。

 

定位內(nèi)存泄漏由于哪一句話引起的你已經(jīng)發(fā)現(xiàn)程序存在內(nèi)存泄漏。現(xiàn)在的問題是,我們要找泄漏的根源。

一般我們首先確定內(nèi)存泄漏是由于哪一句引起。在MFC中,這一點很容易。你雙擊內(nèi)存泄漏報告的文字,或者在Debug窗口中按F4,IDE就幫你定位到申請該內(nèi)存塊的地方。對于上例,也就是這一句:

   int* leak = new int[10];

這多多少少對你分析內(nèi)存泄漏有點幫助。特別地,如果這個new僅對應(yīng)一條delete(或者你把delete漏寫),這將很快可以確認(rèn)問題的癥結(jié)。

我們前面已經(jīng)看到,不使用MFC的時候,生成的內(nèi)存泄漏報告與MFC不同,而且你立刻發(fā)現(xiàn)按F4不靈。那么難道MFC做了什么手腳?

其實不是,我們來模擬下MFC做的事情??聪吕?/p>

 

inline void EnableMemLeakCheck()
{
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}

#ifdef _DEBUG
#define new   new(_NORMAL_BLOCK, __FILE__,__LINE__)
#endif

void main()
{
   EnableMemLeakCheck();
   int* leak = new int[10];
}


再運行這個樣例,你驚喜地發(fā)現(xiàn),現(xiàn)在內(nèi)存泄漏報告和MFC沒有任何分別了。

 第二種方法:直接定位指定內(nèi)存塊錯誤的代碼行(下面轉(zhuǎn))。

單確定了內(nèi)存泄漏發(fā)生在哪一行,有時候并不足夠。特別是同一個new對應(yīng)有多處釋放的情形。在實際的工程中,以下兩種情況很典型:

創(chuàng)建對象的地方是一個類工廠(ClassFactory)模式。很多甚至全部類實例由同一個new創(chuàng)建。對于此,定位到了new出對象的所在行基本沒有多大幫助。 
COM對象。我們知道COM對象采用Reference Count維護生命周期。也就是說,對象new的地方只有一個,但是Release的地方很多,你要一個個排除。 
那么,有什么好辦法,可以迅速定位內(nèi)存泄漏?

答:有。

在內(nèi)存泄漏情況復(fù)雜的時候,你可以用以下方法定位內(nèi)存泄漏。這是我個人認(rèn)為通用的內(nèi)存泄漏追蹤方法中最有效的手段。

我們再回頭看看crtdbg生成的內(nèi)存泄漏報告:

Detected memory leaks!
Dumping objects ->
c:\work\test.cpp(186) : {52} normal block at 0x003C4410, 40 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete. 
除了產(chǎn)生該內(nèi)存泄漏的內(nèi)存分配語句所在的文件名、行號為,我們注意到有一個比較陌生的信息:{52}。這個整數(shù)值代表了什么意思呢?

其實,它代表了第幾次內(nèi)存分配操作。象這個例子,{52}代表了第52次內(nèi)存分配操作發(fā)生了泄漏。你可能要說,我只new過一次,怎么會是第52次?這很容易理解,其他的內(nèi)存申請操作在C的初始化過程調(diào)用的唄。:)

有沒有可能,我們讓程序運行到第52次內(nèi)存分配操作的時候,自動停下來,進入調(diào)試狀態(tài)?所幸,crtdbg確實提供了這樣的函數(shù):即 long _CrtSetBreakAlloc(long nAllocID)。我們加上它:

inline void EnableMemLeakCheck()
{
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}

#ifdef _DEBUG
#define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

void main()
{
   EnableMemLeakCheck();
   _CrtSetBreakAlloc(52);
   int* leak = new int[10];

你發(fā)現(xiàn),程序運行到 int* leak = new int[10]; 一句時,自動停下來進入調(diào)試狀態(tài)。細(xì)細(xì)體會一下,你可以發(fā)現(xiàn),這種方式你獲得的信息遠(yuǎn)比在程序退出時獲得文件名及行號有價值得多。因為報告泄漏文件名及行號,你獲得的只是靜態(tài)的信息,然而_CrtSetBreakAlloc則是把整個現(xiàn)場恢復(fù),你可以通過對函數(shù)調(diào)用棧分析(我發(fā)現(xiàn)很多人不習(xí)慣看函數(shù)調(diào)用棧,如果你屬于這種情況,我強烈推薦你去補上這一課,因為它太重要了)以及其他在線調(diào)試技巧,來分析產(chǎn)生內(nèi)存泄漏的原因。通常情況下,這種分析方法可以在5分鐘內(nèi)找到肇事者。

當(dāng)然,_CrtSetBreakAlloc要求你的程序執(zhí)行過程是可還原的(多次執(zhí)行過程的內(nèi)存分配順序不會發(fā)生變化)。這個假設(shè)在多數(shù)情況下成立。不過,在多線程的情況下,這一點有時難以保證。

 個人心得:我在用這種方法時開始沒看懂,后來在MSDN中也找到了這方面相關(guān)的信息,后來才會用。我感覺在這方面網(wǎng)上介紹的不夠詳細(xì),下面我就相對詳細(xì)地解釋一下(為什么用“相對詳細(xì)”?本人比較懶)。首先說明一下,下面的函數(shù)不需要上面所添加的宏定義和"crtdbg.h"頭文件,也不需要EnableMemLeakCheck()函數(shù)。只需在main函數(shù)一開始運行 _CrtSetBreakAlloc(long (4459))函數(shù)。其中4459是申請內(nèi)存的序號(上面有說明),然后F5運行(不需要設(shè)斷點),然后會出現(xiàn)“Find Source”這個對話框,點擊“取消”。然后會出現(xiàn)“User breakpoint called from code at xxxx”的對話框,點擊“確定”,會看到一些匯編的代碼(不要怕,其實我也看不懂,算然原來學(xué)過點匯編),調(diào)出堆棧窗口(call stack),在其中的“main() line xxx + xxx bytes”上雙擊(或它的上一行雙擊,我的上一行是一個自定義函數(shù),雙擊后直接定位到我new的地方,定位還是很準(zhǔn)的,開始我懷疑,但最后檢查果然是這地方?jīng)]釋放)會定位到錯誤行。


(#)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日韩成人免费性生活视频| 亚洲欧美一二区日韩高清在线| 日本高清一道一二三区四五区| 福利在线午夜绝顶三级| 欧美日韩精品一区免费| 国产精品丝袜美腿一区二区| 日韩日韩日韩日韩在线| 国产级别精品一区二区视频| 国产精品一区二区三区黄色片| 一区二区三区精品人妻| 91后入中出内射在线| 中日韩免费一区二区三区| 久久99午夜福利视频| 99精品国产一区二区青青| 草草视频福利在线观看| 日韩精品你懂的在线观看| 色欧美一区二区三区在线| 日本免费熟女一区二区三区| 欧洲一级片一区二区三区| 自拍偷女厕所拍偷区亚洲综合| 国产又粗又猛又长又黄视频| 日韩欧美中文字幕人妻| 国产又大又硬又粗又湿| 丁香六月婷婷基地伊人| 国产毛片av一区二区三区小说| 麻豆蜜桃星空传媒在线观看| 国产精品欧美激情在线| 欧美日韩精品视频在线| 久久热九九这里只有精品| 国产肥女老熟女激情视频一区| 日韩人妻有码一区二区| 久久碰国产一区二区三区| 色哟哟在线免费一区二区三区| 麻豆一区二区三区在线免费| 自拍偷拍福利视频在线观看| 日韩人妻欧美一区二区久久| 福利视频一区二区在线| 亚洲综合一区二区三区在线| 国产熟女一区二区不卡| 日韩在线免费看中文字幕| 久久精品国产亚洲熟女|