欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
淺談C/C++內存泄漏及其檢測工具

淺談C/C++內存泄漏及其檢測工具(zz)

在csdn上看到一篇不錯的文章,記錄下來(lái)!
 
 
用BoundsChecker檢測內存泄漏:

  BoundsChecker采用一種被稱(chēng)為 Code Injection的技術(shù),來(lái)截獲對分配內存和釋放內存的函數的調用。簡(jiǎn)單地說(shuō),當你的程序開(kāi)始運行時(shí),BoundsChecker的DLL被自動(dòng)載入進(jìn)程的地址空間(這可以通過(guò)system-level的Hook實(shí)現),然后它會(huì )修改進(jìn)程中對內存分配和釋放的函數調用,讓這些調用首先轉入它的代碼,然后再執行原來(lái)的代碼。BoundsChecker在做這些動(dòng)作的時(shí),無(wú)須修改被調試程序的源代碼或工程配置文件,這使得使用它非常的簡(jiǎn)便、直接。

  這里我們以malloc函數為例,截獲其他的函數方法與此類(lèi)似。

  需要被截獲的函數可能在DLL中,也可能在程序的代碼里。比如,如果靜態(tài)連結C-Runtime Library,那么malloc函數的代碼會(huì )被連結到程序里。為了截獲住對這類(lèi)函數的調用,BoundsChecker會(huì )動(dòng)態(tài)修改這些函數的指令。

  以下兩段匯編代碼,一段沒(méi)有BoundsChecker介入,另一段則有BoundsChecker的介入:

126: _CRTIMP void * __cdecl malloc (
127: size_t nSize
128: )
129: {

00403C10 push ebp
00403C11 mov ebp,esp
130: return _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);
00403C13 push 0
00403C15 push 0
00403C17 push 1
00403C19 mov eax,[__newmode (0042376c)]
00403C1E push eax
00403C1F mov ecx,dword ptr [nSize]
00403C22 push ecx
00403C23 call _nh_malloc_dbg (00403c80)
00403C28 add esp,14h
131: }

  以下這一段代碼有BoundsChecker介入:

126: _CRTIMP void * __cdecl malloc (
127: size_t nSize
128: )
129: {

00403C10 jmp 01F41EC8
00403C15 push 0
00403C17 push 1
00403C19 mov eax,[__newmode (0042376c)]
00403C1E push eax
00403C1F mov ecx,dword ptr [nSize]
00403C22 push ecx
00403C23 call _nh_malloc_dbg (00403c80)
00403C28 add esp,14h
131: }

  當BoundsChecker介入后,函數malloc的前三條匯編指令被替換成一條jmp指令,原來(lái)的三條指令被搬到地址01F41EC8處了。當程序進(jìn)入malloc后先jmp到01F41EC8,執行原來(lái)的三條指令,然后就是BoundsChecker的天下了。大致上它會(huì )先記錄函數的返回地址(函數的返回地址在stack上,所以很容易修改),然后把返回地址指向屬于BoundsChecker的代碼,接著(zhù)跳到malloc函數原來(lái)的指令,也就是在00403c15的地方。當malloc函數結束的時(shí)候,由于返回地址被修改,它會(huì )返回到BoundsChecker的代碼中,此時(shí)BoundsChecker會(huì )記錄由malloc分配的內存的指針,然后再跳轉到到原來(lái)的返回地址去。

  如果內存分配/釋放函數在DLL中,BoundsChecker則采用另一種方法來(lái)截獲對這些函數的調用。BoundsChecker通過(guò)修改程序的DLL Import Table讓table中的函數地址指向自己的地址,以達到截獲的目的。

  截獲住這些分配和釋放函數,BoundsChecker就能記錄被分配的內存或資源的生命周期。接下來(lái)的問(wèn)題是如何與源代碼相關(guān),也就是說(shuō)當BoundsChecker檢測到內存泄漏,它如何報告這塊內存塊是哪段代碼分配的。答案是調試信息(Debug Information)。當我們編譯一個(gè)Debug版的程序時(shí),編譯器會(huì )把源代碼和二進(jìn)制代碼之間的對應關(guān)系記錄下來(lái),放到一個(gè)單獨的文件里(.pdb)或者直接連結進(jìn)目標程序,通過(guò)直接讀取調試信息就能得到分配某塊內存的源代碼在哪個(gè)文件,哪一行上。使用Code Injection和Debug Information,使BoundsChecker不但能記錄呼叫分配函數的源代碼的位置,而且還能記錄分配時(shí)的Call Stack,以及Call Stack上的函數的源代碼位置。這在使用像MFC這樣的類(lèi)庫時(shí)非常有用,以下我用一個(gè)例子來(lái)說(shuō)明:


void ShowXItemMenu()
{
 …
 CMenu menu;

 menu.CreatePopupMenu();
 //add menu items.
 menu.TrackPropupMenu();
 …
}

void ShowYItemMenu( )
{
 …
 CMenu menu;
 menu.CreatePopupMenu();
 //add menu items.
 menu.TrackPropupMenu();
 menu.Detach();//this will cause HMENU leak
 …
}

BOOL CMenu::CreatePopupMenu()
{
 …
 hMenu = CreatePopupMenu();
 …
}

  當調用ShowYItemMenu()時(shí),我們故意造成HMENU的泄漏。但是,對于BoundsChecker來(lái)說(shuō)被泄漏的HMENU是在class CMenu::CreatePopupMenu()中分配的。假設的你的程序有許多地方使用了CMenu的CreatePopupMenu()函數,如CMenu::CreatePopupMenu()造成的,你依然無(wú)法確認問(wèn)題的根結到底在哪里,在ShowXItemMenu()中還是在ShowYItemMenu()中,或者還有其它的地方也使用了CreatePopupMenu()?有了Call Stack的信息,問(wèn)題就容易了。BoundsChecker會(huì )如下報告泄漏的HMENU的信息:

Function
File
Line

CMenu::CreatePopupMenu
E:\8168\vc98\mfc\mfc\include\afxwin1.inl
1009

ShowYItemMenu
E:\testmemleak\mytest.cpp
100

  這里省略了其他的函數調用

  如此,我們很容易找到發(fā)生問(wèn)題的函數是ShowYItemMenu()。當使用MFC之類(lèi)的類(lèi)庫編程時(shí),大部分的API調用都被封裝在類(lèi)庫的class里,有了Call Stack信息,我們就可以非常容易的追蹤到真正發(fā)生泄漏的代碼。

  記錄Call Stack信息會(huì )使程序的運行變得非常慢,因此默認情況下BoundsChecker不會(huì )記錄Call Stack信息??梢园凑找韵碌牟襟E打開(kāi)記錄Call Stack信息的選項開(kāi)關(guān):

  1. 打開(kāi)菜單:BoundsChecker|Setting…

  2. 在Error Detection頁(yè)中,在Error Detection Scheme的List中選擇Custom

  3. 在Category的Combox中選擇 Pointer and leak error check

  4. 鉤上Report Call Stack復選框

  5. 點(diǎn)擊Ok

  基于Code Injection,BoundsChecker還提供了API Parameter的校驗功能,memory over run等功能。這些功能對于程序的開(kāi)發(fā)都非常有益。由于這些內容不屬于本文的主題,所以不在此詳述了。

  盡管BoundsChecker的功能如此強大,但是面對隱式內存泄漏仍然顯得蒼白無(wú)力。所以接下來(lái)我們看看如何用Performance Monitor檢測內存泄漏。

  使用Performance Monitor檢測內存泄漏

  NT的內核在設計過(guò)程中已經(jīng)加入了系統監視功能,比如CPU的使用率,內存的使用情況,I/O操作的頻繁度等都作為一個(gè)個(gè)Counter,應用程序可以通過(guò)讀取這些Counter了解整個(gè)系統的或者某個(gè)進(jìn)程的運行狀況。Performance Monitor就是這樣一個(gè)應用程序。

  為了檢測內存泄漏,我們一般可以監視Process對象的Handle Count,Virutal Bytes 和Working Set三個(gè)Counter。Handle Count記錄了進(jìn)程當前打開(kāi)的HANDLE的個(gè)數,監視這個(gè)Counter有助于我們發(fā)現程序是否有Handle泄漏;Virtual Bytes記錄了該進(jìn)程當前在虛地址空間上使用的虛擬內存的大小,NT的內存分配采用了兩步走的方法,首先,在虛地址空間上保留一段空間,這時(shí)操作系統并沒(méi)有分配物理內存,只是保留了一段地址。然后,再提交這段空間,這時(shí)操作系統才會(huì )分配物理內存。所以,Virtual Bytes一般總大于程序的Working Set。監視Virutal Bytes可以幫助我們發(fā)現一些系統底層的問(wèn)題; Working Set記錄了操作系統為進(jìn)程已提交的內存的總量,這個(gè)值和程序申請的內存總量存在密切的關(guān)系,如果程序存在內存的泄漏這個(gè)值會(huì )持續增加,但是Virtual Bytes卻是跳躍式增加的。

  監視這些Counter可以讓我們了解進(jìn)程使用內存的情況,如果發(fā)生了泄漏,即使是隱式內存泄漏,這些Counter的值也會(huì )持續增加。但是,我們知道有問(wèn)題卻不知道哪里有問(wèn)題,所以一般使用Performance Monitor來(lái)驗證是否有內存泄漏,而使用BoundsChecker來(lái)找到和解決。

  當Performance Monitor顯示有內存泄漏,而B(niǎo)oundsChecker卻無(wú)法檢測到,這時(shí)有兩種可能:第一種,發(fā)生了偶發(fā)性?xún)却嫘孤?。這時(shí)你要確保使用Performance Monitor和使用BoundsChecker時(shí),程序的運行環(huán)境和操作方法是一致的。第二種,發(fā)生了隱式的內存泄漏。這時(shí)你要重新審查程序的設計,然后仔細研究Performance Monitor記錄的Counter的值的變化圖,分析其中的變化和程序運行邏輯的關(guān)系,找到一些可能的原因。這是一個(gè)痛苦的過(guò)程,充滿(mǎn)了假設、猜想、驗證、失敗,但這也是一個(gè)積累經(jīng)驗的絕好機會(huì )。

  總結

  內存泄漏是個(gè)大而復雜的問(wèn)題,即使是Java和.Net這樣有Gabarge Collection機制的環(huán)境,也存在著(zhù)泄漏的可能,比如隱式內存泄漏。由于篇幅和能力的限制,本文只能對這個(gè)主題做一個(gè)粗淺的研究。其他的問(wèn)題,比如多模塊下的泄漏檢測,如何在程序運行時(shí)對內存使用情況進(jìn)行分析等等,都是可以深入研究的題目。如果您有什么想法,建議或發(fā)現了某些錯誤,歡迎和我交流。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
C語(yǔ)言運行時(shí)庫詳解
[收藏]C++ Tips(7)--堆內存分配 - 心如止水--coofucoo的專(zhuān)欄
Android Native 內存泄漏系統化解決方案
C 內存泄露及處理方法
C語(yǔ)言中的內存泄漏問(wèn)題
內存泄漏
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久