umdh windbg分析內存泄露


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

1、開啟cmd

                

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

2、利用UMDH創建Heap快照

                

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

程序運行一段時間后或者程序占用內存增加時,然后再次創建heap快照,命令行無差別,snap1.log改為snap2.log或者其他。

3、設置好程序的符號路徑,如下圖

               

4、設置好后可以開始分析heap前后兩個快照的差異

               

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

               

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

                  

這樣我們就可以修改代碼中內存泄露的地方了。

 

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手動分析內存泄露

1、全局標志設置,參照上邊的設置

2、Windbg調試泄露

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

             

命令:!heap –s查看當前進程運行的所有堆的情況

然后F5讓程序運行一段時間或者內存有明顯的增加時再次通過!heap –s查看當前堆的變化,如下圖

              

通過對比前后兩個堆的變化,發現0x012800000該地址的堆增加的很快而其他堆沒什么變化,下面進一步定位

              

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

              

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

           

找到泄露點了,紅色部分的,如果程序對應的符號對應我們可以查看內存泄露點在哪一行

           

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM