• <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>
            隨筆-380  評論-37  文章-0  trackbacks-0

            原帖:http://blog.csdn.net/i_like_cpp/archive/2007/06/28/1669962.aspx
            作者:許式偉 2006年11月某日

            內存管理是C++程序員的痛。我的《內存管理變革》系列就是試圖討論更為有效的內存管理方式,以杜絕(或減少)內存泄漏,減輕C++程序員的負擔。由于工作忙的緣故,這個系列目前未完,暫停。
            ?
            這篇短文我想換個方式,討論一下如何以最快的速度找到內存泄漏。
            ?
            確認是否存在內存泄漏
            我們知道,MFC程序如果檢測到存在內存泄漏,退出程序的時候會在調試窗口提醒內存泄漏。例如:

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

            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也沒有自己做。內存泄漏檢測的工作是VC++的C運行庫做的。也就是說,只要你是VC++程序員,都可以很方便地檢測內存泄漏。我們還是給個樣例:

            #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),你將發現,產生的內存泄漏報告與MFC類似,但有細節不同,如下:

            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.
            為什么呢?看下面。

            定位內存泄漏由于哪一句話引起的
            你已經發現程序存在內存泄漏。現在的問題是,我們要找泄漏的根源。

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

            ?? int* leak = new int[10];

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

            我們前面已經看到,不使用MFC的時候,生成的內存泄漏報告與MFC不同,而且你立刻發現按F4不靈。那么難道MFC做了什么手腳?

            其實不是,我們來模擬下MFC做的事情。看下例:

            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];
            }

            再運行這個樣例,你驚喜地發現,現在內存泄漏報告和MFC沒有任何分別了。

            快速找到內存泄漏
            單確定了內存泄漏發生在哪一行,有時候并不足夠。特別是同一個new對應有多處釋放的情形。在實際的工程中,以下兩種情況很典型:

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

            答:有。

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

            我們再回頭看看crtdbg生成的內存泄漏報告:

            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.
            除了產生該內存泄漏的內存分配語句所在的文件名、行號為,我們注意到有一個比較陌生的信息:{52}。這個整數值代表了什么意思呢?

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

            有沒有可能,我們讓程序運行到第52次內存分配操作的時候,自動停下來,進入調試狀態?所幸,crtdbg確實提供了這樣的函數:即 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];
            }
            你發現,程序運行到 int* leak = new int[10]; 一句時,自動停下來進入調試狀態。細細體會一下,你可以發現,這種方式你獲得的信息遠比在程序退出時獲得文件名及行號有價值得多。因為報告泄漏文件名及行號,你獲得的只是靜態的信息,然而_CrtSetBreakAlloc則是把整個現場恢復,你可以通過對函數調用棧分析(我發現很多人不習慣看函數調用棧,如果你屬于這種情況,我強烈推薦你去補上這一課,因為它太重要了)以及其他在線調試技巧,來分析產生內存泄漏的原因。通常情況下,這種分析方法可以在5分鐘內找到肇事者。

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

            ?


            附加說明:
            對“內存管理”相關的技術感興趣?這里可以看到我的所有關于內存管理的文章。

            ?

            本文來自CSDN博客,轉載請標明出處: http://blog.csdn.net/i_like_cpp/archive/2007/06/28/1669962.aspx

            posted on 2010-01-21 23:14 小王 閱讀(838) 評論(0)  編輯 收藏 引用 所屬分類: c++ 程序設計基礎
            一级女性全黄久久生活片免费| 无码精品久久一区二区三区| 亚洲综合久久夜AV | 久久亚洲精品无码观看不卡| 色偷偷88欧美精品久久久| 久久中文精品无码中文字幕| 久久久久亚洲AV成人网| 久久久久无码专区亚洲av| 一本色道久久88综合日韩精品 | 欧美喷潮久久久XXXXx| 久久久久久精品久久久久| 久久久国产乱子伦精品作者 | 久久精品桃花综合| 久久久www免费人成精品| 久久综合久久自在自线精品自| 91精品国产综合久久精品| 九九热久久免费视频| 日韩电影久久久被窝网| 亚洲国产精品成人久久| 久久不射电影网| 欧美午夜A∨大片久久 | 四虎久久影院| 九九久久自然熟的香蕉图片| 欧美久久一级内射wwwwww.| 日韩精品久久无码中文字幕| 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲 | 久久本道久久综合伊人| 99精品国产综合久久久久五月天| 91久久精一区二区三区大全| 久久天天日天天操综合伊人av| 伊人久久大香线蕉综合Av| 亚洲国产精品久久久久婷婷软件| 人妻少妇精品久久| 国产精品久久久久久久久免费 | 久久久艹| 国产视频久久| 精品人妻伦一二三区久久| 久久影视国产亚洲| 久久久久久国产a免费观看黄色大片| 久久青青国产| 国产精品久久久久久五月尺|