VLD(Visual LeakDetector)內存泄露庫的使用

VLD簡介

    因爲C/C++語言沒有所謂的垃圾收集器,內存的分配和釋放都須要程序員本身來控制,這會給C/C++程序員帶來必定的困難。當您的程序愈來愈複雜時,它的內存管理也會變得愈來愈困難。內存泄漏、內存越界是最多見的內存問題之一。
    內存泄漏若是不是很嚴重的話,在短期內對程序不會形成太大的影響,並且在進程終止的時候,全部分配的內存都會釋放掉。可是對於長時間運行的程序,其破壞力是驚人的,從性能降低到內存耗盡,甚至會影響到其它程序的正常運行。
    此外,內存問題存在一個共同的特色,它自己並不會有很明顯的現象,當有異常出現時就很難檢查問題的緣由所在,這給調試內存問題帶來了很大的難度。
VLD是一款用於VisualC++的免費內存泄漏檢查工具。能夠在codeproject.com網站上找到,相比其它的內存泄漏哦給你根據,他在檢查內存泄漏的同事,還具備以下特色:
    1)  能夠獲得內存泄漏點的調用堆棧,若是能夠的話,還能夠獲得其所在的文件及行號;
    2)  能夠獲得泄漏內存的完整數據;
    3)  惡意設置內存泄漏報告的級別;
    4)  它以動態庫的形式提供,無需編譯源代碼,只須要很小的改動程序;
    5)  源代碼使用GNU許可發佈,並有詳細的文檔及其註釋。
    從使用的角度講,VLD簡單易用,對於使用者本身的代碼中惟一須要修改的地方是#include VLD的頭文件後正常運行本身的程序就能夠發現內存問題。從研究角度上講,若是輸入到VLD源代碼,能夠學習到堆內存分片與釋放的原理、內存檢查的原理機器內存操做的經常使用技巧等。

VLD使用

    VLD網址:http://vld.codeplex.com/
    http://www.codeproject.com/Articles/9815/Visual-Leak-Detector-Enhanced-Memory-Leak-Detectio
    下載Visual LeakDetector,當前版本2.2.3,打開Visual C++ IDE的"工具"→"選項"→"項目和解決方案"→"VC++ 目錄",在"包含文件"中增長VLD的頭文件路徑"\include"路徑,在"庫文件"增長VLD庫文件的"\lib\Win32"路徑,此外動態庫的"\bin\Win32"路徑在安裝時已經添加到環境變量裏面了,如果未添加,則須要手動拷貝"\bin\Win32"下的文件到可執行文件所在的目錄中(拷貝的文件有dbghelp.dll/Microsoft.DTfW.DHL.manifest/vld_x86.dll/vld.ini)。
接下來須要將VLD加入到本身的代碼中。方法很簡單,只要在包含入口函數的.cpp文件中包含vld.h就能夠。若是這個cpp文件中包含了stdafx.h,則將包含vld.h的語句放在stdafx.h的包含語句以後,不然放在最前面。
    示例程序:
#include<vld.h>                 // 包含VLD的頭文件
#include<stdlib.h>
#include<stdio.h>
void f()
{
    int *p = new int(0x12345678);
    printf("p=%08x, ", p);
}
int main()
{
    f();
    return 0;
}
    注:VLD只能在Windows下使用,在包含vld.h頭文件時增長預編譯選項。
    注:在Release模式下,不會連接VisualLeak Detector。
    注:Visual LeakDetector有一些配置項,能夠設置內存泄露報告的保存地(文件、調試器),拷貝"\Visual Leak Detector"路徑下的vld.ini文件到執行文件所在的目錄下(在IDE運行的話,則須要拷貝到工程目錄下),修改如下項:
ReportFile =.\memory_leak_report.txt 
ReportTo = both

VLD工具原理

    下面咱們來看看VLD是如何工做的。在VisualC++中內置工具CRT Debug Heap工具,在使用Debug版本分配內存時,它會在內存塊中記錄分配該內存的文件名和行號。當程序退出時CRT會在main函數返回時作一些清理工做,此時檢查調試堆內存,若是仍然有內存沒釋放,則必定存在內存泄漏問題。從這些沒有被釋放的內存塊的頭中能夠獲得文件名和行號。這種靜態的方法能夠檢查出內存泄漏,可是不知道泄漏到底是怎麼發生的,也不知道該內存分配語句是如何被執行到的,想要了解這些必須對內存分配過程進行動態跟蹤。VLD就是這樣作的,在每次內存分配的時候記錄其上下文,當程序退出時對檢測到的內存泄漏查找其上下文信息,並轉換成報告輸出到Output中。

初始化

    VLD要記錄每次的內存分配,它經過Windows提供的分配鉤子allocation hooks來監視調試堆內存的分配。它是一個用戶自定義的回調函數,在每次從堆中分配內存以前被調用,在初始化是VLD使用_CrtSetAllocation註冊這個鉤子函數。
全局變量在程序初始化時就初始化,若是將VLD做爲一個全局變量就能夠與程序一塊兒啓動,可是C/C++並無約定全局變量初始化的順序,若是其它全局變量的構造函數中有內存分配則可能沒法檢測到。所以,VLD使用C/C++提供的#pragma init_seg來減小其它全局變量在它以前進行初始化。根據#pragma init_seg的定義,全局變量初始化分爲3個階段,首先是compiler階段,通常進行C語言運行時庫的初始化;而後是lib段,通常用於第三方類庫的初始化扽;最後是user段,大部分的初始化都在這個階段進行。

記錄內存分配

    一個內存分配鉤子函數須要具備以下的定義:
int AllocHook(int allocType, void*userData, size_t size,int blockType, long requestNumber, onst unsigned char*filename, int lineNumber);
    該函數須要在VLD初始化時被註冊,每次從堆中分配內存前被調用,它須要處理的事情就是記錄下此時的調用堆棧和此時堆內存分配的惟一標識requestNumber。
獲得當前堆棧的二進制表示並非很複雜的事情,可是由於不一樣的體系結構、不一樣的編譯器、不一樣的操做系統所產生的堆棧內容是不同的,要解釋堆棧並獲得整個函數的調用過程比較複雜。不過Windows提供了一個StackWalk64函數能夠得到堆棧的內容。
    VLD是經常使用的C/C++內存泄漏檢查工具,能夠在ViusalC++中使用,在Viusal Studio 2008和2010中使用須要注意兩點:
    1)  版本問題:VLD已經更新到2.2版本,修正了許多bug,並且在2010版本下工做良好,VisualC++ 6.0推薦使用1.0版本,1.9b版本不是很穩定不建議使用,2.2版本的下載網址爲http://vld.codeplex.com.
    2)  設置變化:VC++Directories設置已經變化位置,在2010中設置過程以下:
View | Other Window | Property Manager
Go to "VC++ Directories" settings
Set include folder path
Set lib folder path
    點OK,咱們就設置好了include和lib目錄。

使用問題

問題1:VLD 1.9

    在vista下使用vld的使用,老是出現錯誤沒法正常工做,後來通過搜索,在http://www.codeproject.com/KB/applications/visualleakdetector.aspx
上的評論中找到了解決的方法:
    評論「Solution forrunning 1.9 beta on Visual Studio 2008 with Vista 」給出瞭解決方法:
評論1:
VLD keptcrashing when trying to use 1.9g beta on Windows Vista, visual studio 2008. Itried all the suggestions on here and nothing worked. But I finally figured itout.
when you make a project in visual C++ 2008,it sets some strange advanced Linker properties that cause VLD to crash:
I changedLinker->Advanced->Randomized Base Address from Enable Image Randomization(/DYNAMICBASE) to Disable Image Randomization (/DYNAMICBASE:NO)
Then I changed Linker->Advanced->DataExecution Prevention from Image is compatible with DEP (/NXCOMPAT) to Default
And now it works perfectly
Please let me know if this helped you!It'll make me feel better for spending a whole day trying to get it working!
 -Nadav
評論2:
The base address randomization seems to benot necessary. Just disable DEP.
   大體的意思是說,只須要禁用DEP便可,
   在工程的「屬性」->「連接器」->「高級」->數據執行保護(DEP),設爲「默認」(default)或者「映像與 DEP 不兼容(/NXCOMPAT:NO)「 便可。(修改後好像不可用)。
  注:這個選項只針對Vista有效!!!

問題2:VLD 2.2.3

    在項目中使用了visual leak detector,調試時程序沒法啓動報錯「應用程序正常啓動失敗(0xc0150002)」。
    解決流程:
    查看vs輸出信息最後一條是:
Theprogram '[3980] MobileSignalAnalyzer.exe: Native' has exited with code-1072365566 (0xc0150002)
    在網上多方查找有:
http://blog.csdn.net/evilswords/article/details/5698851
http://blog.csdn.net/brook0344/article/details/6685724
    這兩篇有解決辦法,就是把VLD中的這兩個複製到執行文件夾下就正常了
Microsoft.VC90.CRT.manifest
Microsoft.DTfW.DHL.manifest
    產生緣由:
    VC200三、VC200五、VC2008及其後續版本,對底層最基本的CRT、MFC、ATL庫都進行了重構,爲了不不一樣版本的庫引發衝突,重構後的庫文件通常放在C://windows/WinSxS 文件夾中,並用特定的文件夾/文件名稱進行標識;
    與VC6不一樣, VC200三、VC200五、VC2008及其後續版本,引入了manifest清單的概念,即應用程序編譯後會同時生成對應的.manifest文件,並將該.manifest文件做爲資源編譯到dll或者exe中去。.manifest文件其實是一個XML格式的文本文件,裏面記錄了dll或exe中要引用的CRT、MFC、ATL庫的版本和名稱。VC6編譯的應用程序對CRT、MFC、ATL的dll都是直接調用,而VC200三、VC200五、VC2008編譯的程序都是先查詢編譯到資源中的manifest中的記錄,而後按照記錄提供的版本和名稱去搜尋對應的CRT、MFC、ATL庫以及隨庫發佈的.manifest文件,搜尋的路徑包括當前目錄、C://windows/WinSxS等等,若是沒有找到對應的庫文件,則提示「應用程序正常初始化失敗」。
相關文章
相關標籤/搜索