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

xiaoguozi's Blog
Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習慣原本生活的人不容易改變,就算現狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預料,人們需要更細心的觀察別人,要隨時注意才能保護別人,因為他們未必知道自己要什么·····

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

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

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

        有了一些基本功能需求,我們需要考慮每種功能怎么去實現。首先,我們可以通過重載的方式來追蹤new,delete.malloc和free,C++給我提供了這樣的特性。因為本文主要針對C++,所以主要講重載new,delete的方法,malloc和free的重載實現于此類似,最終版本的程序中也實現了malloc和free的重載。

1.重載new和delete

        首先我們要了解一下new和delete是怎么工作的。C++中的操作符最終都會被轉換成函數形式,例如"new int"會變成"opetaor new(sizeof(int))",而"new double[10]"會變成"operator new(sizeof(double)*10)",同樣“delete p”就變成了"operator delete(p)"。另外一個需要特別注意的地方是,new對于用戶定義的數據類型(即你的自定義類)會自動調用該類型的構造函數,如果構造函數沒有拋出異常,則正確分配,否則會中斷分配操作,將異常傳遞給用戶。默認情況下,new可以對象構造異常進行捕獲。另外一個版本的new就是不帶捕獲異常功能的的了,所以C++系統提供的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是一個空結構體“struct nothrow_t{}",它的一個實例就是nothrow,C++用它來區分可以捕獲異常的new和不可捕獲異常的new。我們不能直接修改內部函數的行為,但是我們可以重載它們。為了實現提供內存分配信息的功能,我們給重載的函數加上幾個參數。得到以下函數:

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&);
/*******************************/

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

2.空間分配

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

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

2.1.構造函數中的異常

        另外一個必須要注意的一點是,new操作符會先分配空間然后調用用戶自定義類型的構造函數,如果構造函數拋出異常,需要用戶手動釋放已分配的內存。問題在于釋放這樣的內存不能用一般的delete操作符,可以用一個例子來說明:

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釋放已經分配的內存,但是實際上不會釋放。也許你的編譯器會給出這樣一條消息:

        “no matching operator delete found”

        為了正確處理這種情況,并給用戶提供相關的信息,我們需要定義placement delete操作符。placement delete是C++98標準中才有的一個特性,所以對于某些老的編譯器(大致可以認為是指那些98年以前編寫的編譯器)不支持這個特性。這需要在模塊中添加宏定義讓用戶可以關閉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.檢查內存泄露

        有了上面的實現,我們可以方便的手動檢測內存泄露。通過一個函數來實現,它會檢索整個hash表,如果表不為空則存在內存泄露。

        為了達到在最后程序退出時檢查內存泄露的目的,我們需要在所有對象調用析構函數后進行內存泄露檢測,這是因為某些用戶類型在構造函數里調用new而在析構函數里調用delete。這樣做能大大的減小誤報的概率。而且因為對象的析構函數的調用往往在主函數main()執行結束之后進行,所以我們也不能直接在主函數里進行內存泄露檢測。這里我們利用一個全局對象來實現這種檢測。首先我們定義一個類:

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();
            }
        }
};

        這里的構造函數初始化Hash表。析構函數檢測內存泄露。然后定義一個MemCheck的全局靜態對象,這樣當程序運行之前會初始化hash表,程序退出時檢測內存泄露。可是問題又來了,如果一個程序中有多個全局靜態對象會怎樣?不幸的是,對于全局靜態對象的構造順序和析構順序是C++標準中的一個未定義問題,也就是說,這個順序取決于編譯器的具體實現。考慮,絕大多數平臺使用VC和GCC編譯器,我們可以針對這兩種編譯器來控制全局對象的構造和解析順序。

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
;

        這里的宏定義部分都是編譯器的選項。

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

FeedBack:
# re: c++ 內存泄露(轉)
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.   回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            午夜欧美不卡精品aaaaa| 国外成人在线| 欧美一区国产二区| 国产欧美三级| 欧美日韩在线亚洲一区蜜芽| 久久久九九九九| 欧美在线高清| 欧美一级淫片aaaaaaa视频| 亚洲精品激情| 另类av一区二区| 久久精品2019中文字幕| 亚洲欧美一区二区三区在线| 久久久亚洲影院你懂的| 亚洲欧美日韩国产另类专区| 99精品国产99久久久久久福利| 久久久久久午夜| 蜜乳av另类精品一区二区| 久久久久久久尹人综合网亚洲| 欧美在线观看www| 另类图片综合电影| 最新69国产成人精品视频免费| 免费欧美高清视频| 亚洲福利视频在线| 日韩视频一区二区在线观看| 亚洲免费视频网站| 久久综合久久美利坚合众国| 久久尤物视频| 国产精品成人在线| 伊大人香蕉综合8在线视| 激情久久婷婷| 亚洲欧美日韩国产一区二区| 亚洲欧美另类中文字幕| 狼人天天伊人久久| 国产精品视频xxx| 亚洲日本一区二区| 亚洲欧美日韩天堂一区二区| 羞羞视频在线观看欧美| 亚洲高清免费在线| 欧美在线电影| 国产一区二区按摩在线观看| 在线亚洲欧美| 日韩亚洲精品视频| 欧美乱人伦中文字幕在线| 狠狠色综合一区二区| 亚洲女ⅴideoshd黑人| 亚洲黄色大片| 欧美另类videos死尸| 亚洲狼人精品一区二区三区| 久久亚洲精品视频| 欧美影院久久久| 国产亚洲精久久久久久| 国产亚洲综合在线| 激情综合五月天| 麻豆精品精品国产自在97香蕉| 日韩视频中文| 欧美日韩中文另类| 亚洲欧美日韩成人| 香蕉尹人综合在线观看| 黄色成人av| 有坂深雪在线一区| 亚洲黄色高清| 国产精品专区一| 玖玖在线精品| 欧美三区在线视频| 国产精品久久波多野结衣| 亚洲欧美一区在线| 久热精品在线视频| 国产精品嫩草99av在线| 欧美一区深夜视频| 美乳少妇欧美精品| 欧美亚洲尤物久久| 欧美国产激情| 亚洲综合精品四区| 欧美伊久线香蕉线新在线| 日韩一级精品| 久久综合色播五月| 日韩一级精品| 欧美成人一品| 欧美国产综合视频| 亚洲国产岛国毛片在线| 亚洲美女在线国产| 日韩午夜精品视频| 狂野欧美性猛交xxxx巴西| 先锋亚洲精品| 欧美日韩一区二区三区在线看 | 激情一区二区| 亚洲欧美日韩国产一区二区三区| 中文国产一区| 欧美午夜免费电影| 在线视频日韩| 久久久久国产精品厨房| 国产喷白浆一区二区三区| 久久黄金**| 亚洲欧洲精品一区二区三区不卡 | 在线亚洲欧美专区二区| 亚洲一级在线观看| 快播亚洲色图| av成人免费在线观看| 国产婷婷色一区二区三区在线| 亚洲图片欧美一区| 亚洲欧美影音先锋| 韩国欧美一区| 欧美在线影院| 亚洲精品久久久久久一区二区| 亚洲精品免费看| 欧美四级电影网站| 国产精品色一区二区三区| 欧美在线观看一区| 久久噜噜亚洲综合| 欧美激情第1页| 午夜精品久久久久久久99水蜜桃| 欧美日韩国产成人高清视频| 美女视频黄免费的久久| 亚洲精品视频在线看| 国产精品久久久久久久一区探花| 久久九九热免费视频| 亚洲乱亚洲高清| 久久嫩草精品久久久精品| 亚洲天堂视频在线观看| 国产视频在线观看一区二区| 欧美网站大全在线观看| 欧美自拍偷拍| 夜夜嗨一区二区| 欧美激情视频在线免费观看 欧美视频免费一| 亚洲福利小视频| 国产一区二区三区的电影| 国产欧美韩国高清| 国产精品国产三级国产专播精品人 | 国产精品免费aⅴ片在线观看| 久久精品国产综合精品| 99re热精品| 国产精品午夜电影| 国产精品嫩草99av在线| 午夜精品在线视频| 久久国产精品99精品国产| 一本色道久久综合亚洲精品小说 | 亚洲缚视频在线观看| 久久久久久噜噜噜久久久精品| 亚洲欧美日韩在线高清直播| 一本色道综合亚洲| 一区二区三区视频免费在线观看| 国产精品盗摄久久久| 国精品一区二区| 亚洲国产一区二区三区a毛片| 极品尤物av久久免费看| 亚洲第一在线| 中文高清一区| 欧美激情片在线观看| 99re8这里有精品热视频免费 | 国产亚洲精品aa午夜观看| 亚洲综合导航| 国产精品美女久久久久av超清| 国产一区二区三区四区hd| 亚洲第一在线综合在线| 亚洲欧美国内爽妇网| 免费成人在线视频网站| 一区二区免费在线播放| 亚洲欧美日韩另类| 亚洲美女少妇无套啪啪呻吟| 这里只有视频精品| 久久久久久久综合色一本| 国产日韩视频一区二区三区| 亚洲综合电影| 狼狼综合久久久久综合网 | 一区二区三区视频在线播放| 久久免费精品视频| 亚洲国产另类久久精品| 亚洲欧美在线免费| 欧美日韩国产成人| 99国产精品99久久久久久| 免费观看不卡av| 欧美激情网站在线观看| 免费成人av在线看| 激情av一区| 免费久久99精品国产| 亚洲人成网站在线观看播放| 噜噜噜91成人网| 久久本道综合色狠狠五月| 国产精品久久久久久久久久免费看| 亚洲精品一区在线观看| 日韩网站在线看片你懂的| 国产视频久久| 久久国产婷婷国产香蕉| 亚洲午夜久久久久久久久电影院| 欧美日韩在线一区| 欧美在线观看www| 欧美jizz19性欧美| 日韩午夜av在线| 99精品欧美一区二区蜜桃免费| 欧美日韩视频专区在线播放| 亚洲第一搞黄网站| 性色av一区二区三区在线观看 | 久久中文字幕一区二区三区| 久久精品av麻豆的观看方式 | 久久日韩精品| 国产一区 二区 三区一级| 欧美大片在线观看| 国产精品一区二区三区久久久| 美日韩免费视频| 亚洲国产欧美另类丝袜|