一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

內(nèi)存泄露、內(nèi)存溢出以及解決方法

 Y忍冬草 2016-07-12

        最近學習OpenCV,里面經(jīng)常涉及一些內(nèi)存的創(chuàng)建和釋放問題,由于之前一直搞的是機械, 所以不明白這些,在這里查閱了博友:河邊一直柳 的相關(guān)博文,講的不錯(當然里面有些對于現(xiàn)在的自己還不懂),在此轉(zhuǎn)載,以后再拜讀、學習。

轉(zhuǎn)自:http://blog.csdn.net/cjf_iceking/article/details/7552802

內(nèi)存泄露是指程序在運行過程中動態(tài)申請的內(nèi)存空間不再使用后沒有及時釋放,從而很可能導致應(yīng)用程序內(nèi)存無線增長。更廣義的內(nèi)存泄露包括未對系統(tǒng)的資源的及時釋放,比如句柄等。

內(nèi)存溢出即用戶在對其數(shù)據(jù)緩沖區(qū)操作時,超過了其緩沖區(qū)的邊界;尤其是對緩沖區(qū)寫操作時,緩沖區(qū)的溢出很可能導致程序的異常。

一.內(nèi)存泄露

“知己知彼,方能百戰(zhàn)不殆”,如果我們能夠比較清楚的了解在編程的時候哪些情況容易導致內(nèi)存泄露,通過避免這些糟糕的情況,從提高代碼的質(zhì)量本身出發(fā),來抵御潛在導致內(nèi)存泄露的發(fā)生。

1.1先來看看內(nèi)存泄露可能發(fā)生的一些場景:

(1)程序員常常忽略在所有的分支都加上內(nèi)存的回收處理

  1. int size = 100;  
  2. char *pointer = new char[size];  
  3. if (!xxxAPI(pointer, size)  
  4. {  
  5.     return;  
  6. }  
  7. delete[]pointer;  

(2)構(gòu)造函數(shù)中申請空間,析構(gòu)函數(shù)中釋放空間

(3)庫函數(shù)或者系統(tǒng)API會在內(nèi)部申請空間,然后返回指針給用戶;以strdup為例

  1. char *str;  
  2. str = strdup("hello World!");  

  strdup申請了一段空間存儲字符串"hello World",然后返回空間地址,這個時候用戶經(jīng)常會忘記釋放str;

上面只是列出了簡單的三種情況,尤其在一個復雜的大型系統(tǒng)中,一段內(nèi)存的使用周期太長或者嵌套太深,還需要程序員自己去把握。

1.2.內(nèi)存泄露的檢測

(1)利用內(nèi)存泄露檢測工具

常用的有 BoundsCheaker、Deleaker、Visual Leak Detector等,工具畢竟熟能生巧,用戶選擇先自己喜歡的一款去用即可。

BoundsChecker沒有找到win7下支持VS2005的破解版,用盜版的傷不起啊。

(2)使用Deleaker(本文采用vs2005)進行內(nèi)存泄露檢查

如下圖所示:

A) Deleak安裝后自動集成到VS中,在VS“工具”菜單中會加入一個“Deleaker”菜單項。

B) Deleaker能夠?qū)DI,USER對象以及句柄進行檢測,是否及時釋放。

C) Deleaker能夠檢測泄露的內(nèi)存發(fā)生地點,即展示其函數(shù)棧;雙擊能夠轉(zhuǎn)到相應(yīng)的文件;

PS:Deleaker對中文不支持

如果有內(nèi)存泄露Deleaker會在程序調(diào)試完彈出對話框如下圖所示:


(3)使用Viual Leak detector

使用Deleak方便靈活,除了其對中文路徑支持問題,但感覺和vs的集成度并不是很高。

Viual Leak detector安裝后,要在VS中設(shè)置相應(yīng)的頭文件和庫路徑,在Debug模式下如果要檢測相應(yīng)源文件的內(nèi)存泄露,則加上"#include <vld.h>"即可;

這樣在檢測內(nèi)存泄露,可以在VS的輸出窗口進行輸出,感覺和VS的集成度更高,結(jié)果如下圖所示:


同樣能夠顯示 內(nèi)存泄露處的 調(diào)用棧,并且通過雙擊也可以跳轉(zhuǎn)到文件的內(nèi)存泄露行,個人還是比較喜歡這種方式的。

(4)在沒有工具的情況下,使用crtdbg.h中的api也是個很棒的選擇

在MFC中可以看到在程序退出的時候,輸出框內(nèi)結(jié)尾部分輸出內(nèi)存泄露,并且點擊可以跳轉(zhuǎn)到內(nèi)存泄露的代碼處。

那么在console程序下呢,當然我們同樣可以做到(做那些MFC幫我們完成了的細節(jié));

A) _CrtSetDbgFlag函數(shù)

  1. int _CrtSetDbgFlag(  
  2. int newFlag  
  3. );  

(函數(shù)詳細信息參考:http://msdn.microsoft.com/zh-cn/library/5at7yxcs.aspx

這個函數(shù)用于控制debug模式下堆管理的分配行為;

在main函數(shù)開始處添加:

  1. _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);  
  2. //_CRTDBG_REPORT_FLAG:表示獲取當前的標示位  
  3. //_CRTDBG_LEAK_CHECK_DF:表示檢測內(nèi)存泄露  

則如果出現(xiàn)內(nèi)存泄露Debug結(jié)束后,輸出框?qū)⑤敵觯?/p>

{150}表示申請的第150塊申請的內(nèi)存空間;

B) 顯示內(nèi)存泄露所在的文件以及行

能夠知道有內(nèi)存泄露是不夠的,更需要的信息是哪里內(nèi)存泄露了?

我們可以在每個源文件的開頭定義寫這樣一條宏定義:

  1. //根據(jù)__FILE___和__LINE__能夠確定文件和行  
  2. #define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)    


C) 顯示內(nèi)存泄露處的堆棧

  1. //lBreakAlloc,在申請的堆區(qū)序號為lBreakAlloc處設(shè)置一個斷點  
  2. long _CrtSetBreakAlloc( long lBreakAlloc );  
(函數(shù)詳細信息參考:http://technet.microsoft.com/zh-cn/library/aa246759

此函數(shù)在指定的申請堆區(qū)空間次序處(即lBreakAlloc)設(shè)置斷點;

很喜歡這個函數(shù),這個函數(shù)結(jié)合"A)"中提到的{150},比如使用方法:

  1. _CrtSetBreakAlloc(150); //則在第150次申請堆空間時候設(shè)置斷點  

這樣就可以看到函數(shù)調(diào)用棧,從而幫助我們更加精確的定位程序泄露的位置(調(diào)用棧可是個好玩意)。

個人感覺這種方式雖然要手動的修改代碼,但其功能卻比前兩個工具的有效,因為能夠在程序運行的時候查看調(diào)用棧,這就意味著能夠調(diào)試程序

展示結(jié)果如下圖所示(自動在第150次申請堆空間處中斷):


二.內(nèi)存溢出

本篇最想分享的就是內(nèi)存溢出的調(diào)試方法,內(nèi)存溢出能夠?qū)е鲁绦虍惓#疫@種異常使程序員難以下手。

2.1 內(nèi)存溢出導致的異常癥狀

(1)內(nèi)存異常經(jīng)常產(chǎn)生的程序報錯,如下圖所示:

(2)有可能調(diào)試的時候不錯,運行的時候出錯,而且隨機出現(xiàn),這絕對讓人很頭疼的問題。

(3)慶幸的是,如果編譯后的debug程序,直接運行后,如果出錯,可以選擇調(diào)試程序(如下圖所示);

千萬別以為麻煩就此可以解決了,進入調(diào)試狀態(tài)后,發(fā)現(xiàn)出錯的地方根本代碼沒有任何問題,可見內(nèi)存溢出是個多么令人討厭的家伙;

2.2 解決方法

雖然他是那么可惡,但也不要忘了是程序員自己一手創(chuàng)建了出來的。也不要灰心,困難總是有方法去解決的。

(1)等到生病的時候,再去看病,或許已經(jīng)晚了;最好是提前做好預防準備;

        A) 比如在程序中多使用strcpy_s、memcpy_s等具有緩沖區(qū)大小檢查的函數(shù),去取代strcpy、memcpy等;

        B)給工程設(shè)置編譯選項/WX開啟(“將警告視為錯誤”),嚴格要求自己,這樣很可能避免了不少潛在的bug;

        C)  對自己的代碼做好單元測試

(2)如果出現(xiàn)了這種難以查找的錯誤,可以從程序源碼著手,查看一些和內(nèi)存操作相關(guān)的函數(shù),比如strcpy、memcpy等。

本人曾經(jīng)在項目中就遇到用一個項目組成員在使用,strcpy拷貝一個字符串到一個空間不夠的內(nèi)存,從而導致程序異常:

  1. //拷貝字符串,并且返回新的字符串地址  
  2. char * string_copy(const char *source)  
  3. {  
  4.     char *p_string;  
  5.     int string_len;  
  6.     string_len = strlen(source);  
  7.     if(source == NULL)  
  8.     {  
  9.         p_string = (char *)malloc(2*sizeof(char));  
  10.         strcpy(p_string, "");  
  11.     }  
  12.     else  
  13.     {   //這里錯誤 string_len+1  
  14.     p_string = (char *)malloc((string_len)*sizeof(char));   
  15.     strcpy(p_string, source);  
  16.     }  
  17.     return p_string;  
  18. }  

靜態(tài)地去檢查代碼方法比較慢,而且不適用于大工程。

(3)檢查工具

幸運的是本人接觸了一個代碼量較大的工程,不幸的是發(fā)生了內(nèi)存溢出問題,而導致程序異常。而且出現(xiàn)的癥狀,就是調(diào)試不錯,運行出錯,

而且隨機出現(xiàn),并且內(nèi)存異常的代碼處,代碼沒有任何問題。這個問題糾結(jié)了至少一個月,病極亂投醫(yī),但找了一些工具大多用于檢查內(nèi)存泄露的。

最終確定了兩個工具:

A)BoudsChecker,除了能夠檢查內(nèi)存泄露,也能檢查內(nèi)存溢出問題;可惜的是沒有找到Win7 下支持VS2005的破解版本

B)AppVerifier,專門用來檢測那些用普通方法檢測不出的意想不到的bug(比如內(nèi)存溢出、錯誤句柄使用等)。而且AppVerifier使用非常簡單,

只需要綁定需要測試的的應(yīng)用程序,并且勾選測試項后保存,使用VS2005進行調(diào)試即可。AppVier:

PS:文中所稱的內(nèi)存溢出,用英文專業(yè)術(shù)語叫做heap corruption







                                    

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    黄色国产自拍在线观看| 1024你懂的在线视频| 国产精品欧美激情在线| 国产内射一级一片内射高清视频| 激情内射亚洲一区二区三区| 亚洲国产av国产av| 精品日韩欧美一区久久| 国产精品一区欧美二区| 男女午夜在线免费观看视频| 夜夜躁狠狠躁日日躁视频黑人| 亚洲最新一区二区三区| 熟女免费视频一区二区| 欧美日韩欧美国产另类| 欧美人与动牲交a精品| 91偷拍视频久久精品| 中文字幕区自拍偷拍区| 99久久国产精品成人观看| 亚洲国产天堂av成人在线播放| 中日韩美一级特黄大片| 国产精品国三级国产专不卡| 黑人粗大一区二区三区| 久久99精品日韩人妻| 中文字幕有码视频熟女| 国产女性精品一区二区三区| 亚洲黄色在线观看免费高清| 成人午夜视频在线播放| 精品欧美一区二区三久久| 亚洲一二三四区免费视频| 成人精品日韩专区在线观看| 国产在线日韩精品欧美| 成人午夜激情在线免费观看| 黄色日韩欧美在线观看| 国产欧美日韩综合精品二区| 亚洲人午夜精品射精日韩| 日韩在线视频精品中文字幕| 欧美大粗爽一区二区三区| 久久三级国外久久久三级| 国产亚洲中文日韩欧美综合网| 日韩美女偷拍视频久久| 欧美日韩一级黄片免费观看 | 国产亚洲欧美日韩精品一区|