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

xiaoguozi's Blog
Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習(xí)慣原本生活的人不容易改變,就算現(xiàn)狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預(yù)料,人們需要更細(xì)心的觀察別人,要隨時(shí)注意才能保護(hù)別人,因?yàn)樗麄兾幢刂雷约阂裁础ぁぁぁぁ?/span>

 內(nèi)存泄露相信對(duì)C++程序員來說都不陌生。解決內(nèi)存泄露的方案多種多樣,大部分方案以追蹤檢測(cè)為主,這種方法實(shí)現(xiàn)起來容易,使用方便,也比較安全。

         首先我們要確定這個(gè)模塊的主要功能:

  1. 能追蹤內(nèi)存的分配和釋放過程。
  2. 要能顯示內(nèi)存分配的相關(guān)信息,比如內(nèi)存塊大小,代碼所在文件所在行等。
  3. 在發(fā)現(xiàn)內(nèi)存泄露時(shí)及時(shí)給出相關(guān)信息。
  4. 能正確處理一些異常情況,比如內(nèi)存不足,對(duì)象初始化失敗等等。
  5. 是線程安全的。[*這個(gè)還沒有實(shí)現(xiàn)]

        有了一些基本功能需求,我們需要考慮每種功能怎么去實(shí)現(xiàn)。首先,我們可以通過重載的方式來追蹤new,delete.malloc和free,C++給我提供了這樣的特性。因?yàn)楸疚闹饕槍?duì)C++,所以主要講重載new,delete的方法,malloc和free的重載實(shí)現(xiàn)于此類似,最終版本的程序中也實(shí)現(xiàn)了malloc和free的重載。

1.重載new和delete

        首先我們要了解一下new和delete是怎么工作的。C++中的操作符最終都會(huì)被轉(zhuǎn)換成函數(shù)形式,例如"new int"會(huì)變成"opetaor new(sizeof(int))",而"new double[10]"會(huì)變成"operator new(sizeof(double)*10)",同樣“delete p”就變成了"operator delete(p)"。另外一個(gè)需要特別注意的地方是,new對(duì)于用戶定義的數(shù)據(jù)類型(即你的自定義類)會(huì)自動(dòng)調(diào)用該類型的構(gòu)造函數(shù),如果構(gòu)造函數(shù)沒有拋出異常,則正確分配,否則會(huì)中斷分配操作,將異常傳遞給用戶。默認(rèn)情況下,new可以對(duì)象構(gòu)造異常進(jìn)行捕獲。另外一個(gè)版本的new就是不帶捕獲異常功能的的了,所以C++系統(tǒng)提供的new和delete有:

1
2
3
4
5
6
7
8
9
void* operator new(size_t size)throw(std::bad_alloc);
void* operator new[](size_t size) throw(std::bad_alloc);
void* operator new(size_t,std::nothrow_t&)throw();
void* operator new[](size_t,std::nothrow_t&)throw();
 
void  operator delete(void* pointer);
void  operator delete[](void* pointer);
void  operator delete(void* pointer,std::nothrow_t&);
void  operator delete[](void* pointer,std::nothrow_t&);<br>

        其中,nothrow_t是一個(gè)空結(jié)構(gòu)體“struct nothrow_t{}",它的一個(gè)實(shí)例就是nothrow,C++用它來區(qū)分可以捕獲異常的new和不可捕獲異常的new。我們不能直接修改內(nèi)部函數(shù)的行為,但是我們可以重載它們。為了實(shí)現(xiàn)提供內(nèi)存分配信息的功能,我們給重載的函數(shù)加上幾個(gè)參數(shù)。得到以下函數(shù):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void* operator new(size_t size);
void* operator new[](size_t size);
void* operator new(size_t,std::nothrow_t&)throw();
void* operator new[](size_t,std::nothrow_t&)throw();
void* operator new(size_t size,const char* file,const char* func,const int line)throw(std::bad_alloc);
void* operator new[](size_t size,const char* file,const char* func,const int line) throw(std::bad_alloc);
void* operator delete(void* pointer);
void* operator delete[](void* pointer);
/*******Placement Delete********/
void  operator delete(void* pointer,const char* file,const char* func,const int line);
void  operator delete[](void* pointer,const char* file,const char* func,const int line);
void  operator delete(void* pointer,std::nothrow_t&);
void  operator delete[](void* pointer,std::nothrow_t&);
/*******************************/

         中間的幾個(gè)函數(shù),就是我們主要需要重載的函數(shù),模塊的大部分工作也都由著幾個(gè)函數(shù)完成。這些函數(shù)參數(shù)中,file表示分配代碼所在的文件名,func表示代碼所在的函數(shù)名,line表示代碼行號(hào)。這幾個(gè)參數(shù)信息我們可以通過編譯器預(yù)定義好的幾個(gè)宏來獲得:__FILE__,__FUNCTION__,__LINE__。也就是說可以將"new ..."替換成"new(__FILE__,__FUNCTION__,__LINE__) ...",最終成為"operator new(sizeof(...),__FILE__,__FUNCTION__,__LINE__)"的形式,也就達(dá)到了我們的目的。關(guān)于 placement delete將在下面詳細(xì)解釋。

2.空間分配

        接下來我們要考慮內(nèi)存分配信息的組織問題了。我們先來了解一下編譯器是怎么組織的。在大部分編譯器中,new所分配的空間都要大于實(shí)際申請(qǐng)的空間,大出來的部分就是編譯器定義的內(nèi)存塊的信息,包括了內(nèi)存塊的大小還有一些其他信息。如下圖所示:

        我們把包含內(nèi)存分配信息的部分叫做cookie數(shù)據(jù)。為了方便,我們把cookie數(shù)據(jù)放在分配的內(nèi)存的起始位置,之后緊接有效數(shù)據(jù)區(qū)。我們還需要把返回給調(diào)用者的指針和new分配的數(shù)據(jù)區(qū)聯(lián)系起來,原本想用性能比較好的STL的map數(shù)據(jù)結(jié)構(gòu)來儲(chǔ)存這些數(shù)據(jù),但是map內(nèi)部同樣也使用new來分配內(nèi)存,所以如果直接使用map來儲(chǔ)存,就會(huì)陷入死循環(huán)中。所以這里我們必須自己現(xiàn)實(shí)一個(gè)數(shù)據(jù)結(jié)構(gòu)。我們可以對(duì)返回給調(diào)用者的地址進(jìn)行Hash,得到hash 表中的地址,具有相同Hash值的數(shù)據(jù)我們用一個(gè)單向鏈表連接起來。最終的數(shù)據(jù)結(jié)構(gòu)如下圖所示:

2.1.構(gòu)造函數(shù)中的異常

        另外一個(gè)必須要注意的一點(diǎn)是,new操作符會(huì)先分配空間然后調(diào)用用戶自定義類型的構(gòu)造函數(shù),如果構(gòu)造函數(shù)拋出異常,需要用戶手動(dòng)釋放已分配的內(nèi)存。問題在于釋放這樣的內(nèi)存不能用一般的delete操作符,可以用一個(gè)例子來說明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdexcept>
 
void* operator new(size_t size, int line) {
    printf("Allocate %u bytes on line %d\\n", size, line);
    return operator new(size);
}
 
class UserClass {
public:
    UserClass(int n)throw(){
        if(n<=0){
             throw std::runtime_error("n must be positive");
        }
    }
};
 
int main(){
    try{
        UserClass* myobj=new(__LINE__) UserClass(-10);
        delete myobj; //doesn't work if placement was not defined
    } catch(const std::runtime_error& e) {
        fprintf(stderr,"Exception: %s\n",e.what());
    }
    return 0;
}<br>

        這里,雖然在new過后試圖使用delete釋放已經(jīng)分配的內(nèi)存,但是實(shí)際上不會(huì)釋放。也許你的編譯器會(huì)給出這樣一條消息:

        “no matching operator delete found”

        為了正確處理這種情況,并給用戶提供相關(guān)的信息,我們需要定義placement delete操作符。placement delete是C++98標(biāo)準(zhǔn)中才有的一個(gè)特性,所以對(duì)于某些老的編譯器(大致可以認(rèn)為是指那些98年以前編寫的編譯器)不支持這個(gè)特性。這需要在模塊中添加宏定義讓用戶可以關(guān)閉placement delete的定義,以便模塊能在較老的編譯器上編譯。以下就是需要定義的placement delete操作符:

1
2
3
4
void  operator delete(void* pointer,const char* file,const char* func,const int line);
void  operator delete[](void* pointer,const char* file,const char* func,const int line);
void  operator delete(void* pointer,std::nothrow_t&);
void  operator delete[](void* pointer,std::nothrow_t&);<br>

3.檢查內(nèi)存泄露

        有了上面的實(shí)現(xiàn),我們可以方便的手動(dòng)檢測(cè)內(nèi)存泄露。通過一個(gè)函數(shù)來實(shí)現(xiàn),它會(huì)檢索整個(gè)hash表,如果表不為空則存在內(nèi)存泄露。

        為了達(dá)到在最后程序退出時(shí)檢查內(nèi)存泄露的目的,我們需要在所有對(duì)象調(diào)用析構(gòu)函數(shù)后進(jìn)行內(nèi)存泄露檢測(cè),這是因?yàn)槟承┯脩纛愋驮跇?gòu)造函數(shù)里調(diào)用new而在析構(gòu)函數(shù)里調(diào)用delete。這樣做能大大的減小誤報(bào)的概率。而且因?yàn)閷?duì)象的析構(gòu)函數(shù)的調(diào)用往往在主函數(shù)main()執(zhí)行結(jié)束之后進(jìn)行,所以我們也不能直接在主函數(shù)里進(jìn)行內(nèi)存泄露檢測(cè)。這里我們利用一個(gè)全局對(duì)象來實(shí)現(xiàn)這種檢測(cè)。首先我們定義一個(gè)類:

1
2
3
4
5
6
7
8
9
10
11
class MemCheck{
    public:
        MemCheck(){
            memset(pTable,0,sizeof(mc_block_node_t*) * MC_HASHTABLESIZE);
        }
        ~MemCheck(){
            if(mc_checkmem()){
                abort();
            }
        }
};

        這里的構(gòu)造函數(shù)初始化Hash表。析構(gòu)函數(shù)檢測(cè)內(nèi)存泄露。然后定義一個(gè)MemCheck的全局靜態(tài)對(duì)象,這樣當(dāng)程序運(yùn)行之前會(huì)初始化hash表,程序退出時(shí)檢測(cè)內(nèi)存泄露??墒菃栴}又來了,如果一個(gè)程序中有多個(gè)全局靜態(tài)對(duì)象會(huì)怎樣?不幸的是,對(duì)于全局靜態(tài)對(duì)象的構(gòu)造順序和析構(gòu)順序是C++標(biāo)準(zhǔn)中的一個(gè)未定義問題,也就是說,這個(gè)順序取決于編譯器的具體實(shí)現(xiàn)??紤],絕大多數(shù)平臺(tái)使用VC和GCC編譯器,我們可以針對(duì)這兩種編譯器來控制全局對(duì)象的構(gòu)造和解析順序。

1
2
3
4
5
6
7
8
9
#ifdef _MSC_VER
#pragma init_seg(lib)
#endif
 
static MemCheck mc_autocheck_object
#ifdef __GNUC__
__attribute__((init_priority (101)))
#endif
;

        這里的宏定義部分都是編譯器的選項(xiàng)。

posted on 2011-04-05 20:11 小果子 閱讀(1722) 評(píng)論(1)  編輯 收藏 引用 所屬分類: C++

FeedBack:
# re: c++ 內(nèi)存泄露(轉(zhuǎn))
2011-08-04 00:25 | Nelson28CASSANDRA
I opine that to get the <a href="http://bestfinance-blog.com">loans</a> from banks you must present a good reason. However, once I've got a commercial loan, because I wanted to buy a bike.   回復(fù)  更多評(píng)論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产精品久久久久久妇女6080| 久久躁狠狠躁夜夜爽| 国产精品yjizz| 欧美国产日韩免费| 每日更新成人在线视频| 久久久另类综合| 久久久噜噜噜| 免费视频一区| 欧美不卡视频一区| 亚洲国产精品久久久久秋霞不卡| 久久婷婷一区| 欧美大秀在线观看| 亚洲人成人99网站| 亚洲性人人天天夜夜摸| 欧美一区二区黄色| 欧美a一区二区| 国产精品嫩草影院av蜜臀| 国产麻豆精品视频| 91久久精品日日躁夜夜躁欧美 | 国产欧美日韩另类视频免费观看| 国产日产欧产精品推荐色 | 亚洲一区影音先锋| 久久久久久自在自线| 亚洲国产欧美精品| 亚洲一区二区免费视频| 久久资源在线| 国产精品亚洲综合天堂夜夜| 亚洲国产美女精品久久久久∴| 中文在线一区| 欧美国产日本| 欧美一区二区视频观看视频| 欧美区在线观看| 樱桃国产成人精品视频| 午夜精品久久久久久久99热浪潮 | 99精品视频免费在线观看| 亚洲欧美视频在线| 欧美日韩国产精品| 在线成人免费视频| 午夜天堂精品久久久久| 亚洲激情中文1区| 久久久久久久一区二区三区| 国产精品久久看| 亚洲视频日本| 亚洲精品123区| 久久在线观看视频| 国产一区二区三区在线观看精品 | 久久久久久黄| 亚洲尤物视频在线| 欧美午夜精品一区| 一区二区三区高清| 亚洲欧洲一区| 另类酷文…触手系列精品集v1小说| 国产麻豆9l精品三级站| 欧美性开放视频| 在线亚洲美日韩| 亚洲精品综合在线| 欧美久久一区| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 国产精品久久久久久久久动漫| 亚洲精品久久久久久久久| 牛夜精品久久久久久久99黑人 | 亚洲午夜国产一区99re久久 | 久久天天躁狠狠躁夜夜av| 亚洲欧美激情视频在线观看一区二区三区| 欧美日韩岛国| 在线视频欧美一区| 一本大道av伊人久久综合| 欧美日韩一区在线观看视频| 一区二区三区高清在线| 日韩视频在线免费观看| 欧美日韩中文字幕日韩欧美| 亚洲视屏一区| 亚洲一卡二卡三卡四卡五卡| 国产欧美日韩综合一区在线播放| 久久er精品视频| 久久久亚洲国产天美传媒修理工| 亚洲国产电影| 亚洲精品久久久久久久久久久| 欧美日韩精品免费观看视一区二区| 99这里只有久久精品视频| 一区二区三区成人| 国产欧美日韩综合精品二区| 欧美不卡视频一区| 欧美视频一区二区在线观看| 久久xxxx精品视频| 久久夜色精品国产欧美乱| 一本色道久久综合亚洲精品高清 | 亚洲欧美国产va在线影院| 国产综合婷婷| 亚洲欧洲日本一区二区三区| 国产精品网站在线| 麻豆精品视频| 欧美日韩中字| 麻豆精品视频在线| 国产精品护士白丝一区av| 久久久精品国产免大香伊 | 欧美激情视频在线播放 | 亚洲精品一二三区| 国产色视频一区| 亚洲国产成人精品女人久久久| 欧美性jizz18性欧美| 免费成人黄色片| 国产精品美女久久久浪潮软件| 亚洲福利视频三区| 99成人在线| 一区二区亚洲精品国产| 日韩视频一区二区三区在线播放免费观看 | 麻豆国产va免费精品高清在线| 在线亚洲伦理| 久久久午夜视频| 久久精品夜色噜噜亚洲a∨ | 亚洲综合色丁香婷婷六月图片| 久久精品亚洲精品| 亚洲欧美另类久久久精品2019| 久久综合图片| 久久不射网站| 国产精品多人| 亚洲区在线播放| 在线看片一区| 欧美有码在线观看视频| 亚洲伊人一本大道中文字幕| 欧美国产极速在线| 蜜桃精品一区二区三区| 国产欧美 在线欧美| 一本色道久久综合亚洲精品高清 | 亚洲高清视频的网址| 性欧美激情精品| 亚洲欧美日韩区| 国产精品豆花视频| 一本大道久久精品懂色aⅴ| 亚洲国产欧美日韩另类综合| 久久精品三级| 久久综合伊人77777麻豆| 国产精品一区二区三区观看| 亚洲视频综合在线| 亚洲在线一区二区| 欧美日韩在线三级| 亚洲精品资源美女情侣酒店| 99国产精品视频免费观看| 欧美成人精品影院| 亚洲激情不卡| 99热在这里有精品免费| 欧美高清不卡| 亚洲人线精品午夜| 一区二区三区欧美激情| 欧美另类99xxxxx| 99视频精品全部免费在线| 亚洲午夜精品一区二区| 国产精品久久久久久久9999| 99国产欧美久久久精品| 亚洲在线视频观看| 国产日韩欧美三级| 久久久综合视频| 999在线观看精品免费不卡网站| 久色婷婷小香蕉久久| 男女视频一区二区| 日韩午夜免费| 国产精品伦子伦免费视频| 午夜激情综合网| 欧美不卡视频一区发布| 亚洲精品乱码久久久久久蜜桃麻豆| 欧美国产日韩精品| 亚洲香蕉在线观看| 久久久蜜臀国产一区二区| 在线播放日韩专区| 欧美理论电影在线播放| 亚洲一区二区三区欧美| 久久久久久久综合| 最新精品在线| 国产精品天天看| 欧美高清一区二区| 亚洲欧美日韩另类| 欧美国产日韩一区二区在线观看| 亚洲美女av网站| 国产精品看片你懂得| 久久久噜噜噜久久人人看| 亚洲欧洲综合| 久久精品国产第一区二区三区| 在线日韩电影| 国产精品久久久久一区| 另类尿喷潮videofree| 亚洲午夜精品网| 亚洲国产精品久久精品怡红院| 亚洲尤物视频网| 亚洲黄页视频免费观看| 国产精品一二三四区| 免费在线观看成人av| 午夜免费久久久久| 亚洲精品乱码久久久久久黑人| 久久伊人免费视频| 亚洲一区久久久| 亚洲精品123区| 国产亚洲精品v| 欧美性猛片xxxx免费看久爱| 免费的成人av| 久久精品理论片| 亚洲欧美日韩国产综合| 亚洲人体影院| 亚洲风情在线资源站| 另类欧美日韩国产在线|