• <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>

            Thronds

            一問你會(huì)什么 二問你做出過什么 三問你為了什么

              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              36 隨筆 :: 0 文章 :: 56 評(píng)論 :: 0 Trackbacks

            前序:此篇文章為轉(zhuǎn)載,出處不詳,網(wǎng)上對(duì)這篇文章的轉(zhuǎn)載鋪天蓋地,不過這個(gè)只是在VC下面的檢測方法,那么在其他操作系統(tǒng)和編譯平臺(tái)下面,又當(dāng)如何檢測和排除內(nèi)存泄漏呢?文章繼續(xù)補(bǔ)充中..

            摘要:

            本文描述了如何使用VC++CRT庫提供的工具定位和排除內(nèi)存泄漏,檢測的難度使得使用C/C++編程語言的應(yīng)用開發(fā)產(chǎn)生問題。

            介紹:

            動(dòng)態(tài)分配、回收內(nèi)存是C/C++編程語言一個(gè)最強(qiáng)的特點(diǎn),但是中國哲學(xué)家孫(Sun Tzu,我不知道是誰?那位知道?)指出,最強(qiáng)的同時(shí)也是最弱的。這句話對(duì)C/C++應(yīng)用來說非常正確,在內(nèi)存處理出錯(cuò)的地方通常就是BUGS產(chǎn)生的地方。一個(gè)最敏感和難檢測的BUG就是內(nèi)存泄漏-沒有把前邊分配的內(nèi)存成功釋放,一個(gè)小的內(nèi)存泄漏可能不需要太注意,但是程序泄漏大塊內(nèi)存,或者漸增式的泄漏內(nèi)存可能引起的現(xiàn)象是:先是性能低下,再就是引起復(fù)雜的內(nèi)存耗盡錯(cuò)誤。最壞的是,一個(gè)內(nèi)存泄漏程序可能用完了如此多的內(nèi)存以至于引起其他的程序出錯(cuò),留給用戶的是不能知道錯(cuò)誤到底來自哪里。另外,一個(gè)看上去無害的內(nèi)存泄漏可能是另一個(gè)問題的先兆。幸運(yùn)的是VC++DEBUGERCRT庫提供了一組有效的檢測和定位內(nèi)存泄漏的工具。本文描述如何使用這些工具有效和系統(tǒng)的排除內(nèi)存泄漏。

             

            啟動(dòng)內(nèi)存泄漏檢測:

            主要的檢測工具是DEBUGERCRT堆除錯(cuò)函數(shù)。要使除錯(cuò)函數(shù)生效,必須要在你的程序中包含以下幾個(gè)語句:
            #define _CRTDBG_MAP_ALLOC
            #include <stdlib.h>
            #include <crtdbg.h>

            并且這些#include 語句必須按上邊給出的順序使用。如果你改變了順序,可能導(dǎo)致使用的函數(shù)工作不正常。包含crtdbg.h的作用是用mallocfree函數(shù)的debug版本(_malloc_dbg _free_dbg)來替換他們,他們能跟蹤內(nèi)存分配和回收。這個(gè)替換僅僅是在debug狀態(tài)下生效,Relese版本中還是使用普通的mallocfree函數(shù)。

            上面的#define語句使用crt堆函數(shù)相應(yīng)的debug版本來替換正常的堆函數(shù)。這個(gè)語句不是必需的,但是沒有他,你可能會(huì)失去一些有用的內(nèi)存泄漏信息。

            你一旦在你的程序中增加了以上的語句,你可以通過在程序中增加_CrtDumpMemoryLeaks();函數(shù)來輸出內(nèi)存泄漏信息。

            當(dāng)你在debuger下運(yùn)行你的程序時(shí),_CrtDumpMemoryLeaks 顯示內(nèi)存泄漏信息在OutPut窗口的Debug標(biāo)簽項(xiàng)里。內(nèi)存泄漏信息舉例如下:

            Detected memory leaks!
            Dumping objects ->
            C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18}
               normal block at 0x00780E80, 64 bytes long.
             Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
            Object dump complete.
            如果你沒有使用 #define _CRTDBG_MAP_ALLOC語句的話,輸出信息將如下:

            Detected memory leaks!
            Dumping objects ->
            {18} normal block at 0x00780E80, 64 bytes long.
             Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
            Object dump complete.

            像你所看到的,當(dāng)_CRTDBG_MAP_ALLOC 被定義后_CrtDumpMemoryLeaks給了你很多有用的信息。在沒有定義_CRTDBG_MAP_ALLOC 的情況下,顯示信息包含:
            1.
            內(nèi)存分配的編號(hào)(大括弧中的數(shù)字);
            2.
            內(nèi)存快的類型(普通型、客戶端型、CRT型);
            3.16
            進(jìn)制表示的內(nèi)存位置;
            4.
            內(nèi)存快的大小;
            5.
            16bytes的內(nèi)容。

            如果定義了_CRTDBG_MAP_ALLOC ,輸出信息還包含當(dāng)前泄漏內(nèi)存是在那個(gè)文件中被分配的定位信息。文件名后圓括弧中的數(shù)字是行數(shù)。如果你雙擊這行信息,
            C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18}
               normal block at 0x00780E80, 64 bytes long.
            光標(biāo)就會(huì)跳轉(zhuǎn)到原文件中分配這個(gè)內(nèi)存的行前。選擇Output中的題是行,按F4能達(dá)到同樣的效果。

             使用Using _CrtSetDbgFlag
             
            如果你的程序的退出點(diǎn)只有一個(gè)的話,調(diào)用_CrtDumpMemoryLeaks將是非常容易。但是,如果你的程序有多個(gè)退出點(diǎn)話會(huì)是什么樣一個(gè)情況?如果不想在每個(gè)退出點(diǎn)都調(diào)用_CrtDumpMemoryLeaks,你可以在程序的開始包含以下調(diào)用:
            _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
            這個(gè)語句會(huì)在你的程序結(jié)束時(shí)自動(dòng)調(diào)用_CrtDumpMemoryLeaks,但是你必須象前邊提到的那樣設(shè)置_CRTDBG_ALLOC_MEM_DF _CRTDBG_LEAK_CHECK_DF這兩個(gè)標(biāo)志位。

             介紹一下內(nèi)存塊的類型:
             
            就象前面指出的,一個(gè)內(nèi)存泄漏信息指出每個(gè)內(nèi)存泄漏塊的類型為普通、客戶端或者CRT型。在實(shí)際程序中,普通型和客戶端型式最常見的類型。
             
            普通型內(nèi)存塊是你的程序平常分配的內(nèi)存類型。
             
            客戶端型內(nèi)存塊是MFC程序給需要析構(gòu)的對(duì)象分配的內(nèi)存塊。MFCnew操作可以選擇普通型或客戶端型中合適的一種作為將要被創(chuàng)建的對(duì)象的內(nèi)存塊類型。
             CRT
            內(nèi)存塊是CRT庫為自己使用而分配的內(nèi)存塊。CRT在處理自己的釋放內(nèi)存操作時(shí)使用這些塊,所以在內(nèi)存泄漏報(bào)告中這種類型并不常見,除非發(fā)生嚴(yán)重異常(例如:CRT庫出錯(cuò))。
             
            還有兩種類型你在內(nèi)存泄漏信息中看不到:
             
            自由塊,它是已經(jīng)被釋放的內(nèi)存塊;
             
            忽略塊,它是已經(jīng)被特殊標(biāo)示的內(nèi)存塊。

             設(shè)置CRT報(bào)告的格式:
             
            在默認(rèn)情況下,_CrtDumpMemoryLeaks輸出的內(nèi)存泄漏信息就象前邊描述的那樣。你可以使用_CrtSetReportMode讓這些輸出信息輸出到其他地方。如果你使用一個(gè)庫,它可能要使輸出信息到其他的地方,在這種情況下,你可以使用_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );語句使輸出信息重新定位到Output窗口。

             根據(jù)內(nèi)存分配編號(hào)設(shè)置斷點(diǎn):
             
            內(nèi)存泄漏報(bào)告中的文件名和行數(shù)告訴你內(nèi)存泄漏的位置,但是知道內(nèi)存泄漏位置不是總是能找到問題所在。在一個(gè)運(yùn)行的程序中一個(gè)內(nèi)存分配操作可能被調(diào)用多次,但是內(nèi)存泄漏可能只發(fā)生在其中的某次操作中。為了確認(rèn)問題所在,你除了知道泄漏的位置之外,你還必須要知道發(fā)生泄漏的條件。內(nèi)存分配編號(hào)使得解決這個(gè)問題成為可能。這個(gè)數(shù)字就在文件名、行數(shù)之后的大括弧內(nèi)。例如,在上面的輸出中“18”就是內(nèi)存分配編號(hào),它的意思是你程序中的內(nèi)存泄漏發(fā)生在第18次分配操作中。
             CRT
            庫對(duì)正在運(yùn)行程序中所有的內(nèi)存塊分配進(jìn)行計(jì)數(shù),包括自身的內(nèi)存分配,或者其他庫(象MFC)。一個(gè)對(duì)象的分配編號(hào)是n表示第n個(gè)對(duì)象被分配,但是它可能并不表示第N個(gè)對(duì)象通過代碼被分配(在大多數(shù)情況下它們并不相同)。
             
            你可以根據(jù)內(nèi)存分配編號(hào)在內(nèi)存被分配的位置設(shè)置斷點(diǎn)。先在程序開始部分附近設(shè)置一個(gè)斷點(diǎn),當(dāng)你的程序在斷點(diǎn)處停止后,你可以通過QuickWatch對(duì)話框或者Watch窗口來設(shè)置內(nèi)存分配斷點(diǎn)。在Watch窗口中的Name列中輸入_crtBreakAlloc,如果你使用的是多線程DLL版本的CRT庫的話你必須包含上下文轉(zhuǎn)換 {,,msvcrtd.dll}_crtBreakAlloc。完成后按回車,debugger處理這次調(diào)用,并且把返回值顯示在Value列中。如果你沒有設(shè)置內(nèi)存分配斷點(diǎn)的話返回值是-1。在Value列中輸入你想設(shè)置的分配數(shù),例如18
             
            你在自己感興趣的內(nèi)存分配位置設(shè)置斷點(diǎn)后,你可以繼續(xù)debugging。細(xì)心的運(yùn)行你的程序在相同的條件下,這樣才能保證內(nèi)存分配的順序不致發(fā)生變化。當(dāng)程序在特定的內(nèi)存分配處停下來后, 你可以查看Call 窗口和其他的debugger信息來分析此次內(nèi)存分配的條件。如果有必要你可以繼續(xù)運(yùn)行程序,看一看這個(gè)對(duì)象有什么變化,或許可以得知為什么內(nèi)存沒有被正確的釋放。
             
            盡管這個(gè)操作非常容易,但是如果你高興的話也可以在代碼中設(shè)置斷點(diǎn)。在代碼中增加一行代碼_crtBreakAlloc = 18;另外也可以通過_CrtSetBreakAlloc(18)來完成設(shè)置。

             比較內(nèi)存狀態(tài)
             
            另一個(gè)定位內(nèi)存泄漏的方法是在重要位置捕捉應(yīng)用程序的內(nèi)存快照CRT庫提供了一個(gè)結(jié)構(gòu)體類型 _CrtMemState,使用它你可以保存內(nèi)存狀態(tài)的快照(當(dāng)前狀態(tài))。
            _CrtMemState s1, s2, s3;
             
            為了得到一個(gè)快照,可以把一個(gè)_CrtMemState 結(jié)構(gòu)體傳給_CrtMemCheckpoint 函數(shù),這個(gè)函數(shù)可以把當(dāng)前的內(nèi)存狀態(tài)填充在結(jié)構(gòu)體中:
            _CrtMemCheckpoint( &s1 );
             
            你可以通過把結(jié)構(gòu)體_CrtMemState 傳給_CrtMemDumpStatistics函數(shù)來輸出結(jié)構(gòu)體中的內(nèi)容。
            _CrtMemDumpStatistics( &s3 );( &s1 );
             
            它輸出的信息如下:
            0 bytes in 0 Free Blocks.
            0 bytes in 0 Normal Blocks.
            3071 bytes in 16 CRT Blocks.
            0 bytes in 0 Ignore Blocks.
            0 bytes in 0 Client Blocks.
            Largest number used: 3071 bytes.
            Total allocations: 3764 bytes.
             
            為了得知一段代碼中是否有內(nèi)存泄漏,你可以在這段代碼的開始和完成處分別拍一個(gè)快照,然后調(diào)用_CrtMemDifference函數(shù)來比較兩個(gè)狀態(tài):
            _CrtMemCheckpoint( &s1 );
            // memory allocations take place here
            _CrtMemCheckpoint( &s2 );

            if ( _CrtMemDifference( &s3, &s1, &s2) )
               _CrtMemDumpStatistics( &s3 );
             
            就像名字中暗示的那樣,_CrtMemDifference比較兩個(gè)內(nèi)存狀態(tài),并且產(chǎn)生一個(gè)結(jié)果(第一個(gè)參數(shù))。把 _CrtMemCheckpoint 放在程序的開始和結(jié)尾,調(diào)用_CrtMemDifference 來比較結(jié)果,這也是一種檢測內(nèi)存泄漏的方法。如果發(fā)現(xiàn)內(nèi)存泄漏,你可以使用_CrtMemCheckpoint把程序分成兩半分別使用上述方法來檢測內(nèi)存泄漏,這樣就是使用二分法來檢查內(nèi)存泄漏。。、47

            posted on 2008-12-11 12:12 thronds 閱讀(466) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++技術(shù)
            午夜视频久久久久一区| 蜜臀久久99精品久久久久久小说| 久久久精品国产Sm最大网站| 四虎影视久久久免费| 亚洲国产精品无码久久久秋霞2 | 久久精品亚洲精品国产色婷| 精品久久久久一区二区三区| 日韩欧美亚洲综合久久| 久久ZYZ资源站无码中文动漫| 久久精品成人免费观看97| 99久久精品免费看国产一区二区三区 | 色综合久久无码中文字幕| 国产精品熟女福利久久AV| 伊人久久大香线焦AV综合影院| 久久无码av三级| 久久久久人妻精品一区二区三区| 少妇被又大又粗又爽毛片久久黑人 | 久久久无码精品午夜| 久久99精品综合国产首页| 久久久久青草线蕉综合超碰| 国产激情久久久久影院老熟女| 人妻无码αv中文字幕久久| 天天综合久久一二三区| 国产精品久久久久久久午夜片 | 国产精品一久久香蕉国产线看观看| 亚洲人成无码久久电影网站| 精品久久久久久无码免费| 久久精品国产69国产精品亚洲 | 亚洲欧美国产日韩综合久久| 国产福利电影一区二区三区,免费久久久久久久精 | 国产精品久久久久国产A级| 久久久久亚洲AV无码专区首JN| 久久亚洲中文字幕精品一区四| 日本精品久久久中文字幕| 人妻无码中文久久久久专区| 久久国产色av免费看| 奇米影视7777久久精品人人爽| 亚洲精品无码久久久久AV麻豆| 日日狠狠久久偷偷色综合0| 久久久WWW成人免费精品| 日本精品久久久久影院日本|