umdh windbg分析內存泄露

A.利用工具umdh(user-mode dump heap)分析:此處以程序MemoryLeak.exe爲例子async

一、開啓cmd函數

                

鍵入要定位內存泄露的程序gflags.exe /i memroyleak.exe +ust,如圖成功後,開啓memoryleak.exe程序。工具

二、利用UMDH建立Heap快照ui

                

命令格式:umdh -pn:memoryleak.exe -f:snap1.logspa

程序運行一段時間後或者程序佔用內存增長時,而後再次建立heap快照,命令行無差異,snap1.log改成snap2.log或者其餘。命令行

三、設置好程序的符號路徑,以下圖調試

               

四、設置好後能夠開始分析heap先後兩個快照的差別日誌

               

分析差別命令:umdh -d snap1.log snap2.log -f:result.txt,生成的result.txt文件在 命令行同目錄下,這裏是 D:\WinDDK\7600.16385.0\Debuggers code

               

分析完成後查看結果result.txt,紅色爲umdh定位出來的泄露點,咱們在查看源代碼:server

                  

這樣咱們就能夠修改代碼中內存泄露的地方了。

 

B、內存泄露實例分析

兩次快照差別文件實例大體以下:

// Debug library initialized ...  
D0000-111FFF DBGHELP: Server - private symbols & lines   
        C:\FunctionServer\Release\Server.pdb  
77E70000-77FEFFFF DBGHELP: ntdll - public symbols    
        c:\mysymbol\wntdll.pdb\B081677DFC724CC4AC53992627BEEA242\wntdll.pdb  
。。。。  
等等符號加載信息  
  
緊接着是內存泄露信息格式說明   
//                                                                           
// Each log entry has the following syntax:                                   
//                                                                            
// + BYTES_DELTA (NEW_BYTES - OLD_BYTES) NEW_COUNT allocs BackTrace TRACEID   
// + COUNT_DELTA (NEW_COUNT - OLD_COUNT) BackTrace TRACEID allocations        
//     ... stack trace ...                                                    
//                                                                            
// where:                                                                     
//                                                                            
//     BYTES_DELTA - increase in bytes between before and after log           
//     NEW_BYTES - bytes in after log                                         
//     OLD_BYTES - bytes in before log                                        
//     COUNT_DELTA - increase in allocations between before and after log     
//     NEW_COUNT - number of allocations in after log                         
//     OLD_COUNT - number of allocations in before log                        
//     TRACEID - decimal index of the stack trace in the trace database       
//         (can be used to search for allocation instances in the original    
//         UMDH logs).                                                        
//                          
  
接着是具體的內存泄露信息  
  
+    47e0 ( 237238 - 232a58)    1f9 allocs  BackTrace8E5CFAC  
+       4 (   1f9 -   1f5)  BackTrace8E5CFAC    allocations  
  
  
    ntdll!RtlAllocateHeap+274  
    Server!malloc+49 (f:\dd\vctools\crt\crtw32\heap\malloc.c, 92)  
    Server!operator new+1D (f:\dd\vctools\crt\crtw32\heap\new.cpp, 59)  
    Server!CUi::AddItemText+129 (d:\projects\testtest\common\uilibf, 611)  
    Server!CUi::AddItemInt+57 (d:\projects\testtest\common\uilibf, 709)  
    Server!CMainWin::AddOneFunction+1FE (d:\projects\testtest\server\server\, 361)  
    Server!CTest::FunctionPcInfo+3F9 (d:\projects\testtest\server\server\, 306)  
    Server!CTest::FunctionReadDispatch+15D (d:\projects\testtest\server\server\, 105)  
    Server!CTest::FunctionReadCallback+14 (d:\projects\testtest\server\server\, 76)  
    Server!CWSAAsync::ReadProc+10F (d:\projects\testtest\common\wsaasyncselect, 1336)  
    Server!CWSAAsync::ReadProcMiddle+12 (d:\projects\testtest\common\wsaasyncselect, 1296)  
    Server!CWindowsPool::ReadThreadPoolCallback+25 (d:\projects\testtest\common\wsaasyncselect, 332)  
    ntdll!TppWorkpExecuteCallback+10F  
    ntdll!TppWorkerThread+572  
    kernel32!BaseThreadInitThunk+E  
    ntdll!__RtlUserThreadStart+70  
    ntdll!_RtlUserThreadStart+1B  
  
。。。。  
等等其餘內存泄露塊信息 

根據格式的說明可獲得此泄露信息以下:

第一行:+    47e0 ( 237238 - 232a58)    1f9 allocs  BackTrace8E5CFAC

BackTrace8E5CFAC是這個內存塊的標記  237238是生成日誌文件2時該內存塊的大小 232a58是生成日誌文件1該內存塊的大小  差值47e0 是內存泄露的字節數   1f9是分配內存的次數 (其中47e0 我的理解爲申請內存未釋放的字節數,由於有多是釋放的時間未到就生成日誌文件2 形成只有申請內存 沒有釋放的狀況 因此被斷定爲內存泄露 關於這點只是我的意見 不必定正確) 。

第二行:+ 4 ( 1f9 - 1f5) BackTrace8E5CFAC allocations

BackTrace8E5CFAC是內存塊標記和第一行同樣,1f9是生成日誌文件2時該內存分配的次數, 1f5是生成日誌文件1時該內存分配的次數  差值4是此次該內存塊分配的次數。

其餘行:是函數調用堆棧,經過分析本身的程序發現,第三行的 Server!CUi::AddItemText+129 (d:\projects\testtest\common\uilibf, 611) 也是內存泄露所在,對應源代碼是:pItemLabel = new CLabelUI; 這樣基本上就定位到問題所在了

驗證一下觀點:每一次分配的大小是47e0 /4=4600(十進制),  程序中代碼驗證了sizeof(CLabelUI)也等於4600, 看來從日誌1 到日誌2 過程當中這個地方new了4次 可是在日誌2時 還未釋放這些內存 因此形成內存比較時 會定位處該塊內存的泄露,至因而否真泄露仍是要看程序邏輯,可是既然已定位到該代碼 仍是要仔細分析一下 看看是邏輯問題 仍是真忘了釋放內存。

 

B.Windbg手動分析內存泄露

一、全局標誌設置,參照上邊的設置

二、Windbg調試泄露

開啓memoryleak.exe程序,windbg attach到該進程:

             

命令:!heap –s查看當前進程運行的全部堆的狀況

而後F5讓程序運行一段時間或者內存有明顯的增長時再次經過!heap –s查看當前堆的變化,以下圖

              

經過對比先後兩個堆的變化,發現0x012800000該地址的堆增長的很快而其餘堆沒什麼變化,下面進一步定位

              

命令:!heap –stat –h 查看對應對的狀態,發下該堆的內存基本被長度爲0x424的塊佔用,接下來咱們在堆中搜索該進程中哪些模塊佔用0x424長度內存,以下圖

              

命令:!heap –flt s 424, 經過搜索程序內存中的堆發現長度爲424的堆被大量的佔用,進一步查看時誰在使用這個地址

           

找到泄露點了,紅色部分的,若是程序對應的符號對應咱們能夠查看內存泄露點在哪一行