日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内存泄露、内存溢出以及解决方法

發布時間:2024/4/11 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存泄露、内存溢出以及解决方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄(?)[+]

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

內存溢出即用戶在對其數據緩沖區操作時,超過了其緩沖區的邊界;尤其是對緩沖區寫操作時,緩沖區的溢出很可能導致程序的異常。

一.內存泄露

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

1.1先來看看內存泄露可能發生的一些場景:

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

[cpp]?view plaincopy
  • int?size?=?100;??
  • char?*pointer?=?new?char[size];??
  • if?(!xxxAPI(pointer,?size)??
  • {??
  • ????return;??
  • }??
  • delete[]pointer;??
  • (2)構造函數中申請空間,析構函數中釋放空間

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

    [cpp]?view plaincopy
  • char?*str;??
  • str?=?strdup("hello?World!");??
  • ? strdup申請了一段空間存儲字符串"hello World",然后返回空間地址,這個時候用戶經常會忘記釋放str;

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

    1.2.內存泄露的檢測

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

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

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

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

    如下圖所示:

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

    B) Deleaker能夠對GDI,USER對象以及句柄進行檢測,是否及時釋放。

    C) Deleaker能夠檢測泄露的內存發生地點,即展示其函數棧;雙擊能夠轉到相應的文件;

    PS:Deleaker對中文不支持

    如果有內存泄露Deleaker會在程序調試完彈出對話框如下圖所示:


    (3)使用Viual Leak detector

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

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

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


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

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

    在MFC中可以看到在程序退出的時候,輸出框內結尾部分輸出內存泄露,并且點擊可以跳轉到內存泄露的代碼處。

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

    A) _CrtSetDbgFlag函數

    [cpp]?view plaincopy
  • int?_CrtSetDbgFlag(??
  • int?newFlag??
  • );??
  • (函數詳細信息參考:http://msdn.microsoft.com/zh-cn/library/5at7yxcs.aspx)

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

    在main函數開始處添加:

    [cpp]?view plaincopy
  • _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)?|?_CRTDBG_LEAK_CHECK_DF);??
  • //_CRTDBG_REPORT_FLAG:表示獲取當前的標示位??
  • //_CRTDBG_LEAK_CHECK_DF:表示檢測內存泄露??
  • 則如果出現內存泄露Debug結束后,輸出框將輸出:

    {150}表示申請的第150塊申請的內存空間;

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

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

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

    [cpp]?view plaincopy
  • //根據__FILE___和__LINE__能夠確定文件和行??
  • #define?new???new(_NORMAL_BLOCK,?__FILE__,?__LINE__)????


  • C) 顯示內存泄露處的堆棧

    [cpp]?view plaincopy
  • //lBreakAlloc,在申請的堆區序號為lBreakAlloc處設置一個斷點??
  • long?_CrtSetBreakAlloc(?long?lBreakAlloc?);??
  • (函數詳細信息參考:http://technet.microsoft.com/zh-cn/library/aa246759

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

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

    [cpp]?view plaincopy
  • _CrtSetBreakAlloc(150);?//則在第150次申請堆空間時候設置斷點??
  • 這樣就可以看到函數調用棧,從而幫助我們更加精確的定位程序泄露的位置(調用棧可是個好玩意)。

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

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


    二.內存溢出

    本篇最想分享的就是內存溢出的調試方法,內存溢出能夠導致程序異常,而且這種異常使程序員難以下手。

    2.1 內存溢出導致的異常癥狀

    (1)內存異常經常產生的程序報錯,如下圖所示:

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

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

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

    2.2 解決方法

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

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

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

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

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

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

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

    [cpp]?view plaincopy
  • //拷貝字符串,并且返回新的字符串地址??
  • char?*?string_copy(const?char?*source)??
  • {??
  • ????char?*p_string;??
  • ????int?string_len;??
  • ????string_len?=?strlen(source);??
  • ????if(source?==?NULL)??
  • ????{??
  • ????????p_string?=?(char?*)malloc(2*sizeof(char));??
  • ????????strcpy(p_string,?"");??
  • ????}??
  • ????else??
  • ????{???//這里錯誤?string_len+1??
  • ????p_string?=?(char?*)malloc((string_len)*sizeof(char));???
  • ????strcpy(p_string,?source);??
  • ????}??
  • ????return?p_string;??
  • }??
  • 靜態地去檢查代碼方法比較慢,而且不適用于大工程。

    (3)檢查工具

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

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

    最終確定了兩個工具:

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

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

    只需要綁定需要測試的的應用程序,并且勾選測試項后保存,使用VS2005進行調試即可。AppVier:

    PS:文中所稱的內存溢出,用英文專業術語叫做heap corruption

    總結

    以上是生活随笔為你收集整理的内存泄露、内存溢出以及解决方法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。