• <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>
            萬星星@豌豆莢 歡迎加入我們
            一個(gè)吃軟飯的男人!!!!!我只想寫程序####
            微博:http://weibo.com/wanlianwen
            posts - 172,  comments - 1253,  trackbacks - 0


            很久沒有寫技術(shù)方面的東西了,這半年主要是在學(xué)習(xí)別人的東西,對(duì)自己提高比較大,算是一次技術(shù)回籠吧,這次學(xué)習(xí)之旅目的是結(jié)束技術(shù)方面的專注,開始向應(yīng)用方面找突破口,也就是完成技術(shù)積累或者為技術(shù)的積累做堅(jiān)實(shí)的準(zhǔn)備。

            c/C++的一個(gè)讓人瘋狂的地方就是內(nèi)存管理,非法訪問、越界、野指針、泄漏、內(nèi)存分配器等諸多問題,有時(shí)候一個(gè)編程老手也會(huì)迷惘困惑。Crt有一些堆棧檢查的函數(shù)可以完成基本的內(nèi)存狀況檢查,MFC也有一些簡(jiǎn)單的對(duì)象檢查機(jī)制,當(dāng)然好的算是java、.net等sdk的超重量級(jí)封裝了,即使發(fā)生對(duì)象錯(cuò)誤也能把堆棧信息明明白白的告訴你(至少表面上是這樣,具體我對(duì)這兩種語言沒有做過開發(fā))。下面介紹的是某牛公司實(shí)現(xiàn)的內(nèi)存分配工具,基本實(shí)現(xiàn)了內(nèi)存泄漏檢查,對(duì)象合法性檢查,對(duì)于我來說已經(jīng)夠用了。


            為了對(duì)內(nèi)存分配塊進(jìn)行跟蹤,設(shè)計(jì)如下結(jié)構(gòu)體:

            //+--------------------------------------------------------------
            //
            // 每個(gè)請(qǐng)求分配內(nèi)存塊的前綴結(jié)構(gòu)體
            // 用來跟蹤所有請(qǐng)求分配塊以及請(qǐng)求分配名稱
            //
            //---------------------------------------------------------------
            struct DBGALLOCHDR
            {
                DBGALLOCHDR
            *    pdbgahPrev; // 前一個(gè)內(nèi)存塊頭
                DBGALLOCHDR*    pdbgahNext; // 后一個(gè)內(nèi)存塊頭
                DWORD           iAllocated; // 記錄是第幾次請(qǐng)求分配操作
                DWORD           tid;        // 請(qǐng)求分配線程的ID
                size_t          cbRequest;  // 請(qǐng)求分配大小
                char            szName[64]; // 請(qǐng)求分配塊名稱
                DWORD           adwGuard[4];// 保護(hù)頭
            }
            ;

            //+--------------------------------------------------------------
            //
            // 每個(gè)請(qǐng)求分配內(nèi)存塊的后綴結(jié)構(gòu)體
            // 使用特定的數(shù)據(jù)填充用來檢測(cè)指針是合法
            //
            //---------------------------------------------------------------
            struct DBGALLOCFOOT
            {
                DWORD adwGuard[
            4];
            }
            ;

            // 內(nèi)存跟蹤塊的根,通過根可以獲取所有分配塊
            DBGALLOCHDR g_dbgahRoot =
            {
                
            &g_dbgahRoot,
                
            &g_dbgahRoot,
                
            0,
                (DWORD)
            -1
            }
            ;


            為了實(shí)現(xiàn)多線程內(nèi)存分配跟蹤,采用Tls技術(shù)使用線程局部對(duì)象保存當(dāng)前分配信息:
            // 線程局部對(duì)象結(jié)構(gòu)體,輔助實(shí)現(xiàn)每個(gè)線程的請(qǐng)求內(nèi)存分配記錄
            struct DBGTHREADSTATE
            {
                DBGTHREADSTATE
            * ptsNext;
                DBGTHREADSTATE
            * ptsPrev;

                
            // Add globals below
                void*           pvRequest;  // 線程最后一次請(qǐng)求分配內(nèi)存的指針
                size_t          cbRequest;  // 線程最后一次請(qǐng)求分配內(nèi)存的大小
            }
            ;



            // 調(diào)試期間實(shí)際分配內(nèi)存大小=請(qǐng)求分配+分配頭+分配尾
            size_t _ActualSizeFromRequestSize(size_t cb)
            {
                
            return cb+sizeof(DBGALLOCHDR)+sizeof(DBGALLOCFOOT);
            }


            主要實(shí)現(xiàn)的內(nèi)存分配工具有如下這些:
            void*   _MemAlloc(ULONG cb);
            void*   _MemAllocClear(ULONG cb);
            HRESULT _MemRealloc(
            void** ppv, ULONG cb);
            ULONG   _MemGetSize(
            void* pv);
            void    _MemFree(void* pv);
            HRESULT _MemAllocString(LPCTSTR pchSrc, LPTSTR
            * ppchDst);
            HRESULT _MemAllocString(ULONG cch, LPCTSTR pchSrc, LPTSTR
            * ppchDst);
            HRESULT _MemReplaceString(LPCTSTR pchSrc, LPTSTR
            * ppchDest);

            #define MemAlloc(cb)                            _MemAlloc(cb)
            #define MemAllocClear(cb)                       _MemAllocClear(cb)
            #define MemRealloc(ppv, cb)                     _MemRealloc(ppv, cb)
            #define MemGetSize(pv)                          _MemGetSize(pv)
            #define MemFree(pv)                            _MemFree(pv)
            #define MemAllocString(pch, ppch)               _MemAllocString(pch, ppch)
            #define MemAllocStringBuffer(cch, pch, ppch)    _MemAllocString(cch, pch, ppch)
            #define MemReplaceString(pch, ppch)             _MemReplaceString(pch, ppch)
            #define MemFreeString(pch)                      _MemFree(pch)


            通過宏實(shí)現(xiàn)類的new delete重寫:
            #define DECLARE_MEMALLOC_NEW_DELETE() \
                inline 
            void* __cdecl operator new(size_t cb)    return(MemAlloc(cb)); } \
                inline 
            void* __cdecl operator new[](size_t cb)  return(MemAlloc(cb)); } \
                inline 
            void __cdecl operator delete(void* pv)   { MemFree(pv); }

            #define DECLARE_MEMCLEAR_NEW_DELETE() \
                inline 
            void* __cdecl operator new(size_t cb)    return(MemAllocClear(cb)); } \
                inline 
            void* __cdecl operator new[](size_t cb)  return(MemAllocClear(cb)); } \
                inline 
            void __cdecl operator delete(void* pv)   { MemFree(pv); }


            在應(yīng)用的時(shí)候可以重寫全局new delete:
            // 測(cè)試全局new delete
            void* __cdecl operator new(size_t cb)    return(MemAlloc(cb)); }
            void* __cdecl operator new[](size_t cb)  return(MemAlloc(cb)); }
            void __cdecl operator delete(void* pv)   { MemFree(pv); }


            使用注意:
            進(jìn)程啟動(dòng)時(shí)候需要調(diào)用:
            _DbgDllProcessAttach();
            _afxGlobalData._hProcessHeap = GetProcessHeap();

            進(jìn)程退出的時(shí)候需要調(diào)用:
            _DbgDllProcessDetach();

            測(cè)試用例:

            // 測(cè)試基本類型
            void TestBuiltin()
            {
                
            // 基本類型
                int* pInt = new int(10);
                
            int* pIntAry = new int[10];
                
            char* pStr = new char[100];
                MemSetName((pStr, 
            "String"));
            }


            // 測(cè)試class
            void TestClass()
            {
                Cls
            * pCls = new Cls();
            }


            // 測(cè)試釋放
            void TestOk()
            {
                Cls
            * pCls = new Cls();
                delete pCls;
                pCls 
            = NULL;
            }


            DWORD WINAPI ThreadProc(LPVOID lpParameter)
            {
                
            int* pIntAry = new int[100];
                
            return 0;
            }


            // 測(cè)試多線程
            void TestMultiThread()
            {
                HANDLE hHandle 
            = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
                WaitForSingleObject(hHandle, 
            -1);
            }


            int main(int argc, char* argv[])
            {
                _DbgDllProcessAttach();

                _afxGlobalData._hProcessHeap 
            = GetProcessHeap();

                TestBuiltin();
                TestClass();
                TestMultiThread();
                TestOk();

                _DbgDllProcessDetach();
                
            return 0;
            }


            調(diào)試輸出窗口結(jié)果:
            A +    4 -    0 = [      4]
            A +   40 -    0 = [     44]
            A +  100 -    0 = [    144]
            A +    8 -    0 = [    152]
            A +  400 -    0 = [    552]
            The thread 0x1D38 has exited with code 0 (0x0).
            A +    8 -    0 = [    560]
            F +    0 -    8 = [    552]
            ---------- Leaked Memory Blocks ----------
            p=0x00144354  cb=400  #=4    TID:0x1d38
            p=0x00144294  cb=8    #=3    TID:0x1878
            p=0x001441a4  cb=100  #=2    TID:0x1878 String
            p=0x001440ec  cb=40   #=1    TID:0x1878
            p=0x00142a54  cb=4    #=0    TID:0x1878
            total size 552, peak size 560
            ---------- Leaked Memory Blocks End ------


            其中A表示分配 F表示釋放

             

            該工具本人初試沒有中毒癥狀,打算納入個(gè)人小寶庫(kù)中,希望大家喜歡!

            下載

            posted on 2009-06-03 16:16 萬連文 閱讀(2801) 評(píng)論(11)  編輯 收藏 引用 所屬分類: 亂七八糟

            FeedBack:
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-03 16:51 | OwnWaterloo
            operator delete[]呢?  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-03 17:33 | 萬連文
            因?yàn)榈讓訉?shí)現(xiàn)是Heap**操作,所以delete和delete[]都會(huì)調(diào)用HeapFree,所以恰好可以完成任務(wù)。  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-03 21:30 | OwnWaterloo
            @萬連文
            某某牛庫(kù)是哪個(gè)庫(kù)?
            其實(shí)跟有沒有庫(kù)這樣做沒關(guān)系,跟該庫(kù)牛不牛也沒什么關(guān)系。
            不能跟著別人錯(cuò)。

            底層實(shí)現(xiàn)是HeapXXX?
            其實(shí)跟底層實(shí)現(xiàn)到底是什么沒關(guān)系。
            C++標(biāo)準(zhǔn)沒要求底層實(shí)現(xiàn)怎么做, 但是要求重載operator new必須有其對(duì)應(yīng)形式的operator delete重載。


            跟測(cè)不測(cè)試也沒關(guān)系。
            一次不帶TT不會(huì)懷上不等于次次都不會(huì)懷上。
            一個(gè)編譯器上測(cè)試成功,不等于每個(gè)編譯器都能測(cè)試成功。
            在某個(gè)編譯器上能測(cè)試通過,并不能證明或證偽。


            編寫operator new/delete要遵守一些規(guī)范。
            HeapAlloc能否處理 size=0?
            HeapAlloc分配失敗時(shí)的new_hanlder處理?
            對(duì)其他形式new的隱藏?
            "重載"(而不是覆蓋全局標(biāo)準(zhǔn))op new時(shí),如果不提供相應(yīng)形式的op delete,是否也能正確工作?
            與其在不同平臺(tái),不同編譯器,甚至是相同編譯器的不同版本下進(jìn)行測(cè)試,不如一開始就按照標(biāo)準(zhǔn)形式編寫。  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-04 07:42 | 萬連文
            感謝你的指導(dǎo), 我沒有說跨平臺(tái), 也沒有說實(shí)用多個(gè)編譯器,我一直使用VC系列工具在Windows上面寫程序,其他的編譯器和OS了解很少,對(duì)C++標(biāo)準(zhǔn)也研究不夠,出發(fā)點(diǎn)只是想找到一個(gè)經(jīng)過驗(yàn)證的(大的、成功的產(chǎn)品使用過的)簡(jiǎn)便的工具。 我想軟件工具都不是完美的,考慮太多就沒完沒了了,我堅(jiān)持實(shí)用原則。  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-04 10:32 | OwnWaterloo
              1#include <stddef.h>
              2#include <stdlib.h>
              3#include <stdio.h>
              4#include <vector>
              5
              6#include <stdexcept>
              7
              8
              9#if defined(_MSC_VER) && _MSC_VER<1400
             10#include <new.h>
             11namespace std using ::set_new_handler; using ::new_handler; }
             12#else
             13#include <new>
             14#endif
             15
             16
             17void* allocate(size_t size) {
             18    if (size==0) size = 1;
             19    for (void* p=0;;) {
             20        p = malloc(size);
             21        if (p) {
             22            printf("allocate %p\n",p);
             23            return p;
             24        }

             25        std::new_handler handler = std::set_new_handler(0);
             26        std::set_new_handler(handler);
             27        if (handler)
             28            handler();
             29        else
             30            throw std::bad_alloc();
             31    }

             32}

             33
             34void deallocate(void* ptr) {
             35    printf("deallocate %p\n",ptr);
             36    free(ptr);
             37}

             38
             39void* operator new(size_t size) return allocate(size); }
             40void* operator new[](size_t size) return allocate(size); }
             41void operator delete(void* ptr) { deallocate(ptr); }
             42
             43class C {
             44    static int count;
             45public:
             46    static bool fail;
             47    C() {
             48        if (fail)
             49            throw std::exception();
             50        printf("C::C(),%d\n",++count);
             51    }

             52    ~C() {
             53        printf("C::~C(),%d\n",count--);
             54    }

             55    C(const C& ) {
             56        printf("C::(const C&),%d\n",++count);
             57    }

             58
             59
             60    //void* operator new(size_t,void* place) { return place; }
             61    void* operator new(size_t size) return allocate(size); }
             62    void* operator new[](size_t size) return allocate(size); }
             63    void operator delete(void* ptr) { deallocate(ptr); }
             64}
            ;
             65bool C::fail;
             66int C::count;
             67
             68struct S {
             69    static bool fail;
             70    S() {
             71        if (fail)
             72            throw std::exception();
             73        printf("construct\n");
             74    }

             75    ~S() {
             76        printf("destroy\n");
             77    }

             78}
            ;
             79bool S::fail;
             80
             81void test_class(int dim) {
             82    if (dim<=0)
             83        return;
             84    C::fail = dim==4;
             85    C* arr = new C[dim];
             86    delete[]  arr;
             87}

             88
             89
             90void test_global(int dim) {
             91    if (dim<=0)
             92        return;
             93    S::fail = dim==4;
             94    S* arr = new S[dim];
             95    delete[] arr;
             96}

             97
             98int main() {
             99    using namespace std;
            100    int dim = 0;
            101    for (printf("input dim: ");scanf("%d",&dim)==1;printf("input dim: "))
            102    {
            103        try {
            104            test_class(dim);
            105        }

            106        catch (std::exception& ) {
            107            printf("  ---- catch an exception ----\n");
            108        }

            109        try {
            110            test_global(dim);
            111        }

            112        catch (std::exception& ) {
            113            printf("  ---- catch an exception ----\n");
            114        }

            115    }

            116}

            117
             
            有兩個(gè)底層分配函數(shù)allocate和deallocate,它們使用malloc和free。
            用這兩個(gè)函數(shù)實(shí)現(xiàn)全局的3個(gè)op new,op new[], op delete,沒有op delete[]
            還用這兩個(gè)函數(shù)實(shí)現(xiàn)了C的3個(gè)op new,op new[], op delete,同樣沒有op delete[]
            用如下參數(shù)編譯
            cl /EHsc /MD /analyze /W3
             
            你看看結(jié)果吧。
            我用vc8、9測(cè)過(vc6不支持動(dòng)態(tài)crt庫(kù),vc10我沒裝)。
            反正兩處delete[] arr;都沒有調(diào)用 op delete。
            它們調(diào)用那個(gè)全局的,沒有被重寫的op delete[]。
            如果靜態(tài)鏈接,該全局默認(rèn)的op delete[]會(huì)被inline, 再調(diào)用該編譯單元中定義的op delete。
            如果動(dòng)態(tài)鏈接,op delete[]不會(huì)被inline,會(huì)調(diào)用crt庫(kù)中提供的op delete。
            總之,這兩處delete[] arr;都沒有調(diào)用deallocate。
             
            當(dāng)然, 你可以說你只靜態(tài)鏈接到crt庫(kù)。
            也可以說你的allocate和deallocate底層實(shí)現(xiàn)絕對(duì)會(huì)一直保持與vc提供的crt兼容
            但是,你的代碼的用戶了解么?
            難道你打算在文檔中寫“使用我的庫(kù)的代碼者,使用的crt庫(kù)必須滿足XXX要求,必須自己測(cè)試YYY”,只是為了你自己可以少寫一個(gè) op delete[]
            這不是程序庫(kù)開發(fā)者的態(tài)度。
             
            還有兩個(gè)小問題。
            C* pc = static_cast<C*>(malloc(sizeof(*pc));
            new (pc) C; // 編譯錯(cuò)誤
            C* pc2 = new (std::nothrow) C; // 編譯錯(cuò)誤
             
            當(dāng)然, 你還是可以說你絕對(duì)不會(huì)用這種東西, 你是實(shí)用主義嘛。
            但是你的庫(kù)的使用者呢?
             
             
            “出發(fā)點(diǎn)只是想找到一個(gè)經(jīng)過驗(yàn)證的(大的、成功的產(chǎn)品使用過的)簡(jiǎn)便的工具”
            你覺得這可以說明該產(chǎn)品中的每個(gè)細(xì)節(jié)都是無可挑剔的么?
            越是大的產(chǎn)品,測(cè)試越不容易,更不容易暴露其中的問題,同時(shí)也許忽悠客戶也更容易。
             
             
            確實(shí)沒有任何事物都是完美的,但不能連追求完美的心都舍棄了。
            同時(shí),從實(shí)用角度出發(fā),讓該庫(kù)變得更完美,所付出的代價(jià)非常小,“按規(guī)則”辦事就可以了,10來行代碼的事,何樂而不為?
            規(guī)則可以見《EffCpp》或者《C++CodingStandard》。
              回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-04 10:32 | OwnWaterloo
            sorry…… 不小心提交了2次 ……
            我自己刪掉一個(gè) ……  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-04 11:29 | 萬連文
            因?yàn)槲沂强次④涍@么做的,自己確實(shí)沒有發(fā)現(xiàn)什么錯(cuò)誤,我沒法不承認(rèn)她的實(shí)現(xiàn)可以為我所用,可能就是中毒太深吧。您上面寫的那些已經(jīng)超出了我的知識(shí)范圍,我需要好好學(xué)習(xí)。至于 vc6不支持動(dòng)態(tài)crt庫(kù) 好像可以通過修改/MLd到/MDd實(shí)現(xiàn)。  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-04 12:04 | OwnWaterloo
            @萬連文
            微軟的哪? MFC?

            上面的命令行 cl /MD 已經(jīng)告訴編譯器鏈接到動(dòng)態(tài)庫(kù)了。
            vc6不支持是因?yàn)樗挥徐o態(tài)庫(kù)。 crt的動(dòng)態(tài)庫(kù)是跟.net那一套東西一起出來的。  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-04 12:13 | 萬連文
            微軟的什么我沒有必要告訴你,crt的動(dòng)態(tài)庫(kù)我不曉得你怎么想,用dependency工具看看就曉得依賴不依賴了,我對(duì)自己的認(rèn)識(shí)也不是十足的把握。   回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-04 17:59 | 99網(wǎng)上書城
            感謝你的指導(dǎo)  回復(fù)  更多評(píng)論
              
            # re: 技術(shù)回歸01-Windows內(nèi)存分配工具
            2009-06-05 17:50 | Touchsoft
            struct DBGALLOCHDR
            這個(gè)結(jié)構(gòu)好像在調(diào)試時(shí)見到過。  回復(fù)  更多評(píng)論
              
            簡(jiǎn)歷下載
            聯(lián)系我

            <2006年7月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            常用鏈接

            留言簿(66)

            隨筆分類

            隨筆檔案

            相冊(cè)

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久精品无码专区免费青青| 国产精品日韩深夜福利久久| 久久久久久免费视频| 国色天香久久久久久久小说| 久久丫精品国产亚洲av不卡| 国产精品99久久精品爆乳| 成人妇女免费播放久久久| 久久97久久97精品免视看| 久久伊人五月丁香狠狠色| 久久久久免费精品国产| 超级97碰碰碰碰久久久久最新| 日韩十八禁一区二区久久| 2020久久精品国产免费| 久久精品视频一| 久久人人爽人人人人爽AV | 色综合久久综合中文综合网| 91精品免费久久久久久久久| 久久精品国产亚洲AV蜜臀色欲| 久久综合视频网| 久久人人爽人人爽人人爽| 亚洲精品乱码久久久久久蜜桃不卡| 国产精品乱码久久久久久软件 | 国产伊人久久| 久久久久亚洲AV无码专区桃色| 精品国产乱码久久久久久郑州公司 | 中文字幕一区二区三区久久网站| 久久99国产精品久久| 日韩精品久久无码人妻中文字幕| 亚洲国产欧洲综合997久久| 日韩精品久久无码中文字幕| 国产精品久久99| 狠狠精品久久久无码中文字幕 | 无码人妻久久久一区二区三区| 久久精品国产亚洲av高清漫画| 精品久久久久久综合日本| 伊人色综合久久| 亚洲成av人片不卡无码久久| 亚洲色婷婷综合久久| 国产情侣久久久久aⅴ免费| 伊人丁香狠狠色综合久久| 亚洲一区精品伊人久久伊人 |