青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

elva

VC使用CRT調(diào)試功能來檢測內(nèi)存泄漏

C/C++ 編程語言的最強大功能之一便是其動態(tài)分配和釋放內(nèi)存,但是中國有句古話:“最大的長處也可能成為最大的弱點”,那么 C/C++ 應(yīng)用程序正好印證了這句話。在 C/C++ 應(yīng)用程序開發(fā)過程中,動態(tài)分配的內(nèi)存處理不當(dāng)是最常見的問題。其中,最難捉摸也最難檢測的錯誤之一就是內(nèi)存泄漏,即未能正確釋放以前分配的內(nèi)存的錯誤。偶爾發(fā)生的少量內(nèi)存泄漏可能不會引起我們的注意,但泄漏大量內(nèi)存的程序或泄漏日益增多的程序可能會表現(xiàn)出各種 各樣的征兆:從性能不良(并且逐漸降低)到內(nèi)存完全耗盡。更糟的是,泄漏的程序可能會用掉太多內(nèi)存,導(dǎo)致另外一個程序垮掉,而使用戶無從查找問題的真正根源。此外,即使無害的內(nèi)存泄漏也可能殃及池魚。

幸運的是,Visual Studio 調(diào)試器和 C 運行時 (CRT) 庫為我們提供了檢測和識別內(nèi)存泄漏的有效方法。下面請和我一起分享收獲——如何使用 CRT 調(diào)試功能來檢測內(nèi)存泄漏?

一、如何啟用內(nèi)存泄漏檢測機制

  VC++ IDE 的默認(rèn)狀態(tài)是沒有啟用內(nèi)存泄漏檢測機制的,也就是說即使某段代碼有內(nèi)存泄漏,調(diào)試會話的 Output 窗口的 Debug 頁不會輸出有關(guān)內(nèi)存泄漏信息。你必須設(shè)定兩個最基本的機關(guān)來啟用內(nèi)存泄漏檢測機制。

  一是使用調(diào)試堆函數(shù):
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>

#include<crtdbg.h>

注意:#include 語句的順序。如果更改此順序,所使用的函數(shù)可能無法正確工作。

  通過包含 crtdbg.h 頭文件,可以將 malloc 和 free 函數(shù)映射到其“調(diào)試”版本 _malloc_dbg 和 _free_dbg,這些函數(shù)會跟蹤內(nèi)存分配和釋放。此映射只在調(diào)試(Debug)版本(也就是要定義 _DEBUG)中有效。發(fā)行版本(Release)使用普通的 malloc 和 free 函數(shù)。#define 語句將 CRT 堆函數(shù)的基礎(chǔ)版本映射到對應(yīng)的“調(diào)試”版本。該語句不是必須的,但如果沒有該語句,那么有關(guān)內(nèi)存泄漏的信息會不全。

  二是在需要檢測內(nèi)存泄漏的地方添加下面這條語句來輸出內(nèi)存泄漏信息:

_CrtDumpMemoryLeaks();


  當(dāng)在調(diào)試器下運行程序時,_CrtDumpMemoryLeaks 將在 Output 窗口的 Debug 頁中顯示內(nèi)存泄漏信息。比如: Detected memory leaks!
Dumping objects ->

C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.

Data: <AB> 41 42



c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {44} normal
block at 0x00441BD0, 33 bytes long.

Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD



c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {43} normal
block at 0x00441C20, 40 bytes long.

Data: < C > 08 02 43 00 16 00 00 00 00 00 00 00 00 00 00 00



Object dump complete.

如果不使用 #define _CRTDBG_MAP_ALLOC 語句,內(nèi)存泄漏的輸出是這樣的:


Detected memory leaks!

Dumping objects ->

{45} normal block at 0x00441BA0, 2 bytes long.
Data: <AB> 41 42

{44} normal block at 0x00441BD0, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD

{43} normal block at 0x00441C20, 40 bytes long.
Data: < C > C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00

Object dump complete.



  根據(jù)這段輸出信息,你無法知道在哪個源程序文件里發(fā)生了內(nèi)存泄漏。下面我們來研究一下輸出信息的格式。第一行和第二行沒有什么可說的,從第三行開始:


xx}:花括弧內(nèi)的數(shù)字是內(nèi)存分配序號,本文例子中是 {45},{44},{43};
block:內(nèi)存塊的類型,常用的有三種:normal(普通)、client(客戶端)或 CRT(運行時);本文例子中是:normal block;
用十六進(jìn)制格式表示的內(nèi)存位置,如:at 0x00441BA0 等;
以字節(jié)為單位表示的內(nèi)存塊的大小,如:32 bytes long;
前 16 字節(jié)的內(nèi)容(也是用十六進(jìn)制格式表示),如:Data: 41 42 等;


  仔細(xì)觀察不難發(fā)現(xiàn),如果定義了 _CRTDBG_MAP_ALLOC ,那么在內(nèi)存分配序號前面還會顯示在其中分配泄漏內(nèi)存的文件名,以及文件名后括號中的數(shù)字表示發(fā)生泄漏的代碼行號,比如:


C:\Temp\memleak\memleak.cpp(15)


  雙擊 Output 窗口中此文件名所在的輸出行,便可跳到源程序文件分配該內(nèi)存的代碼行(也可以選中該行,然后按 F4,效果一樣) ,這樣一來我們就很容易定位內(nèi)存泄漏是在哪里發(fā)生的了,因此,_CRTDBG_MAP_ALLOC 的作用顯而易見。

使用 _CrtSetDbgFlag
  如果程序只有一個出口,那么調(diào)用 _CrtDumpMemoryLeaks 的位置是很容易選擇的。但是,如果程序可能會在多個地方退出該怎么辦呢?在每一個可能的出口處調(diào)用 _CrtDumpMemoryLeaks 肯定是不可取的,那么這時可以在程序開始處包含下面的調(diào)用:_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );這條語句無論程序在什么地方退出都會自動調(diào)用 _CrtDumpMemoryLeaks。注意:這里必須同時設(shè)置兩個位域標(biāo)志:_CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF。

設(shè)置 CRT 報告模式
  默認(rèn)情況下,_CrtDumpMemoryLeaks 將內(nèi)存泄漏信息 dump 到 Output 窗口的 Debug 頁, 如果你想將這個輸出定向到別的地方,可以使用 _CrtSetReportMode 進(jìn)行重置。如果你使用某個庫,它可能將輸出定向到另一位置。此時,只要使用以下語句將輸出位置設(shè)回 Output 窗口即可:


_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );

  有關(guān)使用 _CrtSetReportMode 的詳細(xì)信息,請參考 MSDN 庫關(guān)于 _CrtSetReportMode 的描述。

二、解釋內(nèi)存塊類型

  前面已經(jīng)說過,內(nèi)存泄漏報告中把每一塊泄漏的內(nèi)存分為 normal(普通塊)、client(客戶端塊)和 CRT 塊。事實上,需要留心和注意的也就是 normal 和 client,即普通塊和客戶端塊。
  1.normal block(普通塊):這是由你的程序分配的內(nèi)存。
  2.client block(客戶塊):這是一種特殊類型的內(nèi)存塊,專門用于 MFC 程序中需要析構(gòu)函數(shù)的對象。MFC new 操作符視具體情況既可以為所創(chuàng)建的對象建立普通塊,也可以為之建立客戶塊。
  3.CRT block(CRT 塊):是由 C RunTime Library 供自己使用而分配的內(nèi)存塊。由 CRT 庫自己來管理這些內(nèi)存的分配與釋放,我們一般不會在內(nèi)存泄漏報告中發(fā)現(xiàn) CRT 內(nèi)存泄漏,除非程序發(fā)生了嚴(yán)重的錯誤(例如 CRT 庫崩潰)。

  除了上述的類型外,還有下面這兩種類型的內(nèi)存塊,它們不會出現(xiàn)在內(nèi)存泄漏報告中:
  1.free block(空閑塊):已經(jīng)被釋放(free)的內(nèi)存塊。
  2.Ignore block(忽略塊):這是程序員顯式聲明過不要在內(nèi)存泄漏報告中出現(xiàn)的內(nèi)存塊。

三、如何在內(nèi)存分配序號處設(shè)置斷點

  在內(nèi)存泄漏報告中,的文件名和行號可告訴分配泄漏的內(nèi)存的代碼位置,但僅僅依賴這些信息來了解完整的泄漏原因是不夠的。因為一個程序在運行時,一段分配內(nèi)存的代碼可能會被調(diào)用很多次,只要有一次調(diào)用后沒有釋放內(nèi)存就會導(dǎo)致內(nèi)存泄漏。為了確定是哪些內(nèi)存沒有被釋放,不僅要知道泄漏的內(nèi)存是在哪里分配的,還要知道泄漏產(chǎn)生的條件。這時內(nèi)存分配序號就顯得特別有用——這個序號就是文件名和行號之后的花括弧里的那個數(shù)字。


  例如,在本文例子代碼的輸出信息中,“45”是內(nèi)存分配序號,意思是泄漏的內(nèi)存是你程序中分配的第四十五個內(nèi)存塊:


Detected memory leaks!

Dumping objects ->

C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.

Data: <AB> 41 42

......

Object dump complete.


  CRT 庫對程序運行期間分配的所有內(nèi)存塊進(jìn)行計數(shù),包括由 CRT 庫自己分配的內(nèi)存和其它庫(如 MFC)分配的內(nèi)存。因此,分配序號為 N 的對象即為程序中分配的第 N 個對象,但不一定是代碼分配的第 N 個對象。(大多數(shù)情況下并非如此。)這樣的話,你便可以利用分配序號在分配內(nèi)存的位置設(shè)置一個斷點。方法是在程序起始附近設(shè)置一個位置斷點。當(dāng)程序在該點中斷時,可以從 QuickWatch(快速監(jiān)視)對話框或 Watch(監(jiān)視)窗口設(shè)置一個內(nèi)存分配斷點:

  例如,在 Watch 窗口中,在 Name 欄鍵入下面的表達(dá)式:


_crtBreakAlloc


  如果要使用 CRT 庫的多線程 DLL 版本(/MD 選項),那么必須包含上下文操作符,像這樣:


{,,msvcrtd.dll}_crtBreakAlloc


  現(xiàn)在按下回車鍵,調(diào)試器將計算該值并把結(jié)果放入 Value 欄。如果沒有在內(nèi)存分配點設(shè)置任何斷點,該值將為 –1。

  用你想要在其位置中斷的內(nèi)存分配的分配序號替換 Value 欄中的值。例如輸入 45。這樣就會在分配序號為 45 的地方中斷。

  在所感興趣的內(nèi)存分配處設(shè)置斷點后,可以繼續(xù)調(diào)試。這時,運行程序時一定要小心,要保證內(nèi)存塊分配的順序不會改變。當(dāng)程序在指定的內(nèi)存分配處中斷時,可以查看 Call Stack(調(diào)用堆棧)窗口和其它調(diào)試器信息以確定分配內(nèi)存時的情況。如果必要,可以從該點繼續(xù)執(zhí)行程序,以查看對象發(fā)生了什么情況,或許可以確定未正確釋放對象的原因。

  盡管通常在調(diào)試器中設(shè)置內(nèi)存分配斷點更方便,但如果愿意,也可在代碼中設(shè)置這些斷點。為了在代碼中設(shè)置一個內(nèi)存分配斷點,可以增加這樣一行(對于第四十五個內(nèi)存分配):


_crtBreakAlloc = 45;


  你還可以使用有相同效果的 _CrtSetBreakAlloc 函數(shù):


_CrtSetBreakAlloc(45);



四、如何比較內(nèi)存狀態(tài)

  定位內(nèi)存泄漏的另一個方法就是在關(guān)鍵點獲取應(yīng)用程序內(nèi)存狀態(tài)的快照。CRT 庫提供了一個結(jié)構(gòu)類型 _CrtMemState。你可以用它來存儲內(nèi)存狀態(tài)的快照:


_CrtMemState s1, s2, s3;


  若要獲取給定點的內(nèi)存狀態(tài)快照,可以向 _CrtMemCheckpoint 函數(shù)傳遞一個 _CrtMemState 結(jié)構(gòu)。該函數(shù)用當(dāng)前內(nèi)存狀態(tài)的快照填充此結(jié)構(gòu):


_CrtMemCheckpoint( &s1 );


  通過向 _CrtMemDumpStatistics 函數(shù)傳遞 _CrtMemState 結(jié)構(gòu),可以在任意地方 dump 該結(jié)構(gòu)的內(nèi)容:


_CrtMemDumpStatistics( &s1 );


  該函數(shù)輸出如下格式的 dump 內(nèi)存分配信息:


0 bytes in 0 Free Blocks.
75 bytes in 3 Normal Blocks.
5037 bytes in 41 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 5308 bytes.
Total allocations: 7559 bytes.


  若要確定某段代碼中是否發(fā)生了內(nèi)存泄漏,可以通過獲取該段代碼之前和之后的內(nèi)存狀態(tài)快照,然后使用 _CrtMemDifference 比較這兩個狀態(tài):


_CrtMemCheckpoint( &s1 );// 獲取第一個內(nèi)存狀態(tài)快照

// 在這里進(jìn)行內(nèi)存分配

_CrtMemCheckpoint( &s2 );// 獲取第二個內(nèi)存狀態(tài)快照

// 比較兩個內(nèi)存快照的差異
if ( _CrtMemDifference( &s3, &s1, &s2) )
_CrtMemDumpStatistics( &s3 );// dump 差異結(jié)果


  顧名思義,_CrtMemDifference 比較兩個內(nèi)存狀態(tài)(前兩個參數(shù)),生成這兩個狀態(tài)之間差異的結(jié)果(第三個參數(shù))。在程序的開始和結(jié)尾放置 _CrtMemCheckpoint 調(diào)用,并使用 _CrtMemDifference 比較結(jié)果,是檢查內(nèi)存泄漏的另一種方法。如果檢測到泄漏,則可以使用 _CrtMemCheckpoint 調(diào)用通過二進(jìn)制搜索技術(shù)來分割程序和定位泄漏。



五、結(jié)論

  盡管 VC ++ 具有一套專門調(diào)試 MFC 應(yīng)用程序的機制,但本文上述討論的內(nèi)存分配很簡單,沒有涉及到 MFC 對象,所以這些內(nèi)容同樣也適用于 MFC 程序。在 MSDN 庫中可以找到很多有關(guān) VC++ 調(diào)試方面的資料,如果你能善用 MSDN 庫,相信用不了多少時間你就有可能成為調(diào)試高手。

posted on 2009-05-06 14:55 葉子 閱讀(1402) 評論(1)  編輯 收藏 引用 所屬分類: C\C++

Feedback

# re: VC使用CRT調(diào)試功能來檢測內(nèi)存泄漏 2010-07-22 15:43 johnrambo

好文!  回復(fù)  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲视频电影图片偷拍一区| 欧美韩日一区二区三区| 亚洲性夜色噜噜噜7777| 国产精品久久久久久久久久久久久久 | 久久久爽爽爽美女图片| 久久成人免费日本黄色| 亚洲第一精品夜夜躁人人爽 | 欧美亚洲三级| 久久久99爱| 日韩写真在线| 亚洲影视九九影院在线观看| 国产视频自拍一区| 欧美韩国日本综合| 国产精品欧美在线| 美日韩精品视频免费看| 欧美激情国产高清| 亚洲性感美女99在线| 在线 亚洲欧美在线综合一区| 一本一道久久综合狠狠老精东影业| 99视频+国产日韩欧美| 国产精品羞羞答答xxdd| 美日韩精品视频| 国产精品久久久一区二区三区| 久久影视精品| 欧美日韩在线不卡| 免费日韩精品中文字幕视频在线| 欧美日本一区| 免费观看成人www动漫视频| 欧美午夜激情小视频| 老司机午夜精品| 国产精品成人播放| 欧美激情成人在线| 国产精品区免费视频| 亚洲国产精品精华液2区45| 欧美性猛交xxxx免费看久久久 | 亚洲高清不卡一区| 亚洲一区二区少妇| 亚洲美女精品久久| 久久久久在线| 欧美在线欧美在线| 欧美三日本三级少妇三2023| 欧美激情第一页xxx| 国产综合激情| 香蕉尹人综合在线观看| 中文在线资源观看网站视频免费不卡| 久久视频一区二区| 久久另类ts人妖一区二区| 国产精品99免费看 | 香蕉av777xxx色综合一区| 欧美激情在线| 欧美激情一区二区三区高清视频| 伊大人香蕉综合8在线视| 亚洲欧美另类综合偷拍| 亚洲欧美日韩国产成人精品影院| 欧美日韩成人| 亚洲日本乱码在线观看| 亚洲精品日韩一| 免费永久网站黄欧美| 欧美成人一区二区在线| 在线日韩av片| 免费观看一级特黄欧美大片| 欧美激情精品久久久久久变态| 激情av一区二区| 久久精品亚洲热| 美女999久久久精品视频| 在线观看的日韩av| 久久人人爽国产| 欧美大片免费看| 亚洲国产欧美在线| 欧美精品高清视频| 夜夜爽av福利精品导航| 亚洲欧美日韩在线综合| 国产精品视频99| 午夜精品电影| 老色鬼久久亚洲一区二区| 国内精品久久久久久久影视麻豆| 久久久九九九九| 欧美激情区在线播放| 99re热精品| 国产精品毛片高清在线完整版| 亚洲一区国产| 久久久久一本一区二区青青蜜月| 欧美日韩喷水| 在线免费观看日韩欧美| 欧美岛国在线观看| 亚洲最新视频在线| 先锋资源久久| 亚洲国产精彩中文乱码av在线播放| 欧美69wwwcom| 在线综合亚洲| 久久一区欧美| 一本色道久久综合亚洲精品小说| 国产精品每日更新| 久久看片网站| a91a精品视频在线观看| 久久久精品国产免大香伊| 亚洲精品一区二区网址| 国产欧美一区二区三区久久人妖 | aa日韩免费精品视频一| 久久av一区二区| 亚洲精品之草原avav久久| 国产精品三级久久久久久电影| 久久精品国产一区二区三区免费看| 亚洲经典自拍| 久久久成人精品| 在线亚洲一区观看| 亚洲高清不卡在线| 国产欧美大片| 欧美日韩免费观看一区=区三区| 欧美亚洲色图校园春色| 亚洲欧洲精品一区二区精品久久久| 午夜亚洲伦理| av不卡在线看| 136国产福利精品导航网址| 国产精品男gay被猛男狂揉视频| 免费亚洲电影| 欧美一区二区三区婷婷月色| 99国内精品久久| 欧美黄免费看| 美女视频一区免费观看| 欧美在线视频网站| 亚洲欧美国产日韩天堂区| 亚洲人www| 亚洲国产91色在线| 狠狠狠色丁香婷婷综合久久五月| 国产精品爽爽爽| 欧美日韩综合久久| 欧美人体xx| 欧美精品在线观看一区二区| 男男成人高潮片免费网站| 欧美在线亚洲在线| 午夜一级久久| 亚洲欧美韩国| 亚洲视频碰碰| 一本色道久久综合亚洲精品不 | 久久亚洲色图| 久久九九国产精品| 欧美专区第一页| 欧美在线观看一区二区| 欧美在线观看视频| 欧美专区日韩视频| 久久久91精品国产一区二区三区 | 久久免费一区| 久久久久一区| 欧美福利一区二区三区| 欧美寡妇偷汉性猛交| 免播放器亚洲一区| 免费视频久久| 亚洲日本欧美在线| 亚洲精选久久| 亚洲一区精品在线| 先锋影音久久久| 久久国产精品久久久| 久久久777| 欧美精品久久一区二区| 欧美福利视频网站| 欧美日韩中文另类| 国产精品午夜电影| 国内精品久久久久影院色| 在线观看国产一区二区| 亚洲精品久久久久中文字幕欢迎你| 亚洲精品国产日韩| 亚洲午夜在线视频| 久久久久久午夜| 欧美激情欧美狂野欧美精品| av成人动漫| 久久精品国产欧美亚洲人人爽| 免播放器亚洲| 国产精品免费一区二区三区在线观看 | 欧美一级理论片| 玖玖在线精品| 日韩一级片网址| 欧美一区二区三区婷婷月色| 欧美福利一区| 国产农村妇女精品一二区| 一区三区视频| 亚洲视频在线观看三级| 久久久久久久久久久久久久一区 | 亚洲国产一区二区三区a毛片| 亚洲网站在线播放| 久久综合综合久久综合| 欧美性猛片xxxx免费看久爱| 在线精品视频一区二区三四| 亚洲一区二区三区四区五区午夜| 久久网站免费| 亚洲深夜av| 欧美激情一级片一区二区| 国产欧美日韩视频一区二区| 日韩视频在线观看免费| 久久精品综合| 亚洲一区二区高清| 猛男gaygay欧美视频| 国产女主播一区二区| 99这里有精品| 欧美大片免费久久精品三p| 欧美一级理论性理论a| 欧美小视频在线观看| 亚洲级视频在线观看免费1级| 欧美在线观看一区| 中文亚洲欧美|