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

            loop_in_codes

            低調(diào)做技術(shù)__歡迎移步我的獨(dú)立博客 codemaro.com 微博 kevinlynx

            自己寫內(nèi)存泄露檢測(cè)庫(kù)

            author: kevin lynx

            這個(gè)內(nèi)存泄露工具最基本的原理就是利用宏替換掉標(biāo)準(zhǔn)的malloc、free(暫不考慮其他內(nèi)存分配函數(shù),
            如realloc、strdup),記錄下每次內(nèi)存分配和釋放動(dòng)作。因?yàn)楹甑奶幚戆l(fā)生在預(yù)處理階段,所以可以
            很容易地用你自己的malloc函數(shù)替換掉標(biāo)準(zhǔn)的malloc。例如:

            /* lib.h */
            #define malloc my_malloc
            #define free my_free 

            /* lib.c */
            /* disable these macro in this compile unit */
            #undef malloc
            #undef free 

            static int count = 0

            void *my_malloc( size_t size )
            {
                
            ++count;
                
            return malloc( size );
            }
             

            void my_free( void *a )
            {
                
            --count;
                free( a );
            }
             


            要使用以上代碼,用戶在使用時(shí)就需要包含lib.h,從而可以使用宏將用戶自己寫的malloc替換
            為my_mallo。當(dāng)程序退出時(shí),如果count大于0,那么可以肯定的是有內(nèi)存泄露。當(dāng)然,如果
            count為負(fù)數(shù),則很可能對(duì)同一個(gè)指針進(jìn)行多次free。

            但是以上代碼的功能太局限了。一個(gè)真正的內(nèi)存泄露檢測(cè)庫(kù)(工具),至少需要報(bào)告泄露的代碼
            文件、函數(shù)、行數(shù)等信息。當(dāng)然,如果能報(bào)告調(diào)用堆棧,就更好了。不過(guò)這就依賴于具體的平臺(tái),
            需要使用特定的系統(tǒng)接口才可以獲取出。

            要實(shí)現(xiàn)以上功能也很簡(jiǎn)單,只需要在每次調(diào)用malloc的時(shí)候,通過(guò)編譯器預(yù)定義宏__FILE__、
            __LINE__、__FUNCTION__(__func__)就可以得到文件名、函數(shù)、行號(hào)等信息。將這些信息保存
            起來(lái),然后在free的時(shí)候移除相應(yīng)的信息即可。

            最簡(jiǎn)單的實(shí)現(xiàn)方式,就是保存一個(gè)表,表里記錄著每次分配內(nèi)存的信息:

             

            struct memRecord
            {
                
            char file[MAX_FILE_NAME];
                
            char func[MAX_FUNC_NAME];
                size_t lineno;
                
            void *address;
                size_t size;
            }


            struct memRecord mem_record[MAX_RECORD]; 

             

            但是,通過(guò)單單一個(gè)free函數(shù)的void*參數(shù),如何獲取出對(duì)應(yīng)的分配記錄呢?難道:

            for( size_t i = 0; i < MAX_RECORD; ++ i )
            {
                
            if( address == mem_record[i].address ) 
                
            {
                    
            /* shit */
                }

            }
             

             

            雖然可行,但是很stupid。這里提供一個(gè)小技巧:

             

            void *my_malloc( size_t size )
            {
                
            void *= malloc( size + sizeof( size_t ) );
                
            return (char*)a + sizeof( size_t );
            }
             

            void my_free( void *a )
            {
                
            /* actually, 'a' is not the real address */
                
            char *= ((char*)a - sizeof( size_t ) );    
                free( p );
            }

             

            意思就是說(shuō),我多分配了4字節(jié)內(nèi)存(sizeof( size_t ) ),用于保存這次分配記錄在mem_record
            中被保存的索引。在釋放內(nèi)存的時(shí)候,通過(guò)一些地址偏移計(jì)算,就可以獲取出真正的系統(tǒng)malloc
            返回的地址,從而安全釋放(別給我說(shuō)這里的計(jì)算存在平臺(tái)和編譯器的限制,沒(méi)認(rèn)真看文章的SB才說(shuō))。

            另一個(gè)問(wèn)題是,我們?nèi)绾翁幚砻看畏峙溽尫艜r(shí),對(duì)于分配記錄那個(gè)數(shù)據(jù)結(jié)構(gòu),也就是mem_record。
            每一次free的時(shí)候,移除的記錄可能位于mem_record的任何位置。一定時(shí)間后,mem_record內(nèi)部
            將出現(xiàn)很多漏洞(已經(jīng)沒(méi)用的數(shù)組位置)。解決這個(gè)問(wèn)題最直接當(dāng)然還是最stupid的方法,就是每次
            free移除記錄時(shí)重新整理一遍mem_record。如果你這樣做了,那你的malloc/free比微軟的還慢。

            我的解決方法是:
            size_t free_index[MAX_RECORD];
            用于保存這些出現(xiàn)漏洞的index。每一次free移除記錄時(shí),就把這個(gè)記錄對(duì)應(yīng)的inex保存進(jìn)來(lái),表示
            這個(gè)index指向的mem_record[]可用。每一次malloc的時(shí)候,先從這里取index,如果這里沒(méi)有,那
            可以直接從mem_record的末尾取。

            具體細(xì)節(jié)就不闡述了,典型的空間換時(shí)間方法。整個(gè)庫(kù)很簡(jiǎn)單,代碼100來(lái)行。我也只進(jìn)行過(guò)粗略的
            測(cè)試。我肯定這100來(lái)行代碼是有問(wèn)題的,相信自己的代碼存在問(wèn)題是對(duì)bug的一種覺(jué)悟,哈哈哈。

            這個(gè)東西只檢測(cè)C語(yǔ)言的內(nèi)存泄露,其實(shí)要檢測(cè)C++的也很簡(jiǎn)單,只需要重載new和delete就可以了。

            要放春節(jié)假了,在公司的最后幾個(gè)小時(shí)實(shí)在無(wú)聊,才做了這個(gè)東西,前后花了1個(gè)多小時(shí),寫起來(lái)感覺(jué)
            不錯(cuò)。

             

             

            代碼下載

             

            posted on 2009-01-23 17:43 Kevin Lynx 閱讀(4394) 評(píng)論(5)  編輯 收藏 引用 所屬分類: c/c++

            評(píng)論

            # re: 自己寫內(nèi)存泄露檢測(cè)庫(kù) 2009-01-23 22:53 jims

            本人一直博主學(xué)習(xí)  回復(fù)  更多評(píng)論   

            # re: 自己寫內(nèi)存泄露檢測(cè)庫(kù) 2009-01-23 23:04 adon

            char *str = (char*) malloc( 100 );
            char *str2 = (char*) malloc( 111 );
            str = str2;
            free(str);
            free(str);
            getchar();

            Memory leak report by cmlc, a tiny c memory leak checking library.
            Detected 0 memory leaks.

            似乎在free上出了點(diǎn)問(wèn)題  回復(fù)  更多評(píng)論   

            # re: 自己寫內(nèi)存泄露檢測(cè)庫(kù) 2009-01-23 23:28 adon

            static void cmlc_remove_record( size_t index )
            {
            if( fi_tail < MAX_RECORD - 1 )
            {
            free_index[fi_tail++] = index;
            free(mem_record[index].address);
            mem_record[index].address = 0; /* to identify this record has been removed */
            }
            }

            void cmlc_free( void *address )
            {
            struct memory *mem = (struct memory*)( (char*)address - sizeof( size_t ) );
            cmlc_remove_record( mem->index );
            // free( mem ); //注釋的free,移到cmlc_remove_record中
            }  回復(fù)  更多評(píng)論   

            # re: 自己寫內(nèi)存泄露檢測(cè)庫(kù) 2009-01-23 23:55 萬(wàn)連文

            需要考慮多線程,否則太不安全了,沒(méi)有實(shí)際意義。  回復(fù)  更多評(píng)論   

            # re: 自己寫內(nèi)存泄露檢測(cè)庫(kù) 2009-01-24 20:55 陳梓瀚(vczh)

            微軟的編譯器僅需在cpp開(kāi)始的地方:
            #define _CRTDBG_MAP_ALLOC
            #include <stdlib.h>
            #include <crtdbg.h>

            當(dāng)你認(rèn)為東西都是放完了以后調(diào)用
            _CrtDumpMemoryLeaks();

            東西就回到output窗口去了。  回復(fù)  更多評(píng)論   

            久久亚洲春色中文字幕久久久| 亚洲午夜久久久精品影院| 中文字幕无码av激情不卡久久| 久久笫一福利免费导航| 久久久久亚洲av无码专区| 久久精品中文字幕久久| 热99RE久久精品这里都是精品免费| 久久久久久久波多野结衣高潮 | 久久精品国产99国产精品澳门| 国产精品gz久久久| 久久国产劲爆AV内射—百度| 国产69精品久久久久777| 亚洲国产成人久久一区WWW| 国产情侣久久久久aⅴ免费| 午夜精品久久久久久| 精品无码久久久久久尤物| 亚洲国产婷婷香蕉久久久久久| 国产精品99精品久久免费| 久久这里有精品| 国产69精品久久久久99尤物| 777午夜精品久久av蜜臀| 久久99精品久久久久久齐齐| 丁香五月网久久综合| 亚洲AV无码久久| 一级女性全黄久久生活片免费 | 精品久久久久久久久午夜福利| 99热热久久这里只有精品68| 亚洲中文字幕无码久久2017| 久久久精品波多野结衣| 2021国产成人精品久久| 少妇高潮惨叫久久久久久| 国产香蕉久久精品综合网| 久久强奷乱码老熟女| 超级碰久久免费公开视频| 2021久久国自产拍精品| 日本强好片久久久久久AAA | 国产日韩欧美久久| 久久最近最新中文字幕大全| 久久电影网一区| 久久久久久免费一区二区三区| 国产午夜精品久久久久免费视 |