使用 UMDH 尋找User-Mode記憶體流失
使用者模式傾印堆積 (UMDH) 公用程式可搭配作業系統使用,以分析特定進程的 Windows 堆積配置。 UMDH 會找出特定進程中的常式流失記憶體。
UMDH 包含在 Windows 的偵錯工具中。 如需完整詳細資料,請參閱 UMDH。
準備使用 UMDH
如果您尚未判斷哪一個進程正在流失記憶體,請先執行此動作。 如需詳細資訊,請參閱使用效能監視器尋找User-Mode記憶體流失。
UMDH 記錄中最重要的資料是堆積配置的堆疊追蹤。 若要判斷進程是否流失堆積記憶體,請分析這些堆疊追蹤。
使用 UMDH 顯示堆疊追蹤資料之前,您必須使用 GFlags 來正確設定系統。 GFlags 包含在 Windows 的偵錯工具中。
下列 GFlags 設定會啟用 UMDH 堆疊追蹤:
在 GFlags 圖形化介面中,選擇 [影像檔] 索引標籤,輸入進程名稱 (包括副檔名) 、按 TAB 鍵、選取 [建立使用者模式堆疊追蹤資料庫],然後選取 [ 套用]。
或者,同樣地,請使用下列 GFlags 命令列,其中 ImageName 是進程名稱 (包括副檔名) :
gflags /i ImageName +ust
完成之後,請使用此命令清除 GFlag 設定。 如需詳細資訊,請參閱 GFlags 命令。
gflags /i ImageName -ust
根據預設,Windows 收集的堆疊追蹤資料量限制為 x86 處理器上的 32 MB,x64 處理器上則限制為 64 MB。 如果您必須增加此資料庫的大小,請在 GFlags 圖形化介面中選擇 [影像檔] 索引標籤、輸入進程名稱、按 TAB 鍵、核取 [堆疊回溯 (Megs ) ] 核取方塊、在相關聯的文字方塊中輸入 MB) 的值 (,然後選取 [ 套用]。 只有在需要時才增加此資料庫,因為它可能會耗用有限的 Windows 資源。 當您不再需要較大的大小時,請將此設定傳回至其原始值。
如果您在 [系統登錄 ] 索引標籤上變更了任何旗標,則必須重新開機 Windows,才能讓這些變更生效。 如果您在 [ 影像檔] 索引標籤上變更了任何旗標,則必須重新開機程式,讓變更生效。 [ 核心旗標] 索引標籤 的變更會立即生效,但在下次 Windows 重新開機時會遺失。
使用 UMDH 之前,您必須能夠存取應用程式的適當符號。 UMDH 會使用環境變數所指定的符號路徑_NT_SYMBOL_PATH。 將此變數設定為等於包含您應用程式符號的路徑。 如果您也包含 Windows 符號的路徑,分析可能更完整。 這個符號路徑的語法與偵錯工具所使用的語法相同;如需詳細資訊,請參閱 符號路徑。
例如,如果您的應用程式符號位於 C:\MySymbols,而您想要使用 Windows 符號的公用 Microsoft 符號存放區,使用 C:\MyCache 作為下游存放區,您可以使用下列命令來設定符號路徑:
set _NT_SYMBOL_PATH=c:\mysymbols;srv*c:\mycache*https://msdl.microsoft.com/download/symbols
此外,若要確保正確結果,您必須停用 BSTR 快取。 若要這樣做,請將 OANOCACHE 環境變數設定為 1 (1) 。 在啟動要追蹤其配置的應用程式之前,請先進行此設定。
如果您需要追蹤服務所做的配置,您必須將 OANOCACHE 設定為系統內容變數,然後重新開機 Windows,讓此設定生效。
使用 UMDH 偵測堆積配置增加
進行這些準備之後,您可以使用 UMDH 來擷取進程堆積配置的相關資訊。 若要這樣做,請遵循此程式:
決定您想要調查之 進程的進程識別碼 (PID) 。
使用 UMDH 分析此程式的堆積記憶體配置,並將它儲存至記錄檔。 搭配 PID 使用 -p 參數,以及具有記錄檔名稱的 -f 參數。 例如,如果 PID 為 124,而且您想要將記錄檔命名為 Log1.txt,請使用下列命令:
umdh -p:124 -f:log1.txt
使用記事本或其他程式開啟記錄檔。 此檔案包含每個堆積配置的呼叫堆疊、透過該呼叫堆疊所做的配置數目,以及透過該呼叫堆疊取用的位元組數目。
因為您要尋找記憶體流失,所以單一記錄檔的內容不足。 您必須比較在不同時間記錄的記錄檔,以判斷哪些配置正在成長。
UMDH 可以比較兩個不同的記錄檔,並在各自的配置大小中顯示變更。 您可以使用大於符號 () > ,將結果重新導向至第三個文字檔。 您也可以包含 -d 選項,以將位元組和配置計數從十六進位轉換為十進位。 例如,若要比較Log1.txt和Log2.txt,請將比較的結果儲存至檔案LogCompare.txt,請使用下列命令:
umdh log1.txt log2.txt > logcompare.txt
開啟LogCompare.txt檔案。 其內容如下所示:
+ 5320 ( f110 - 9df0) 3a allocs BackTrace00B53 Total increase == 5320
針對 UMDH 記錄檔中標示為 「BackTrace」) 的每個呼叫 (堆疊,兩個記錄檔之間會有比較。 在此範例中,第一個記錄檔 (Log1.txt) 記錄為 BackTrace00B53 配置的0x9DF0位元組,而第二個記錄檔則記錄0xF110位元組,這表示擷取兩個記錄檔之間已配置0x5320額外的位元組。 位元組來自 BackTrace00B53 所識別的呼叫堆疊。
若要判斷該回溯的內容,請開啟其中一個原始記錄檔 (例如,Log2.txt) 並搜尋 「BackTrace00B53」。結果類似于此資料:
00005320 bytes in 0x14 allocations (@ 0x00000428) by: BackTrace00B53 ntdll!RtlDebugAllocateHeap+0x000000FD ntdll!RtlAllocateHeapSlowly+0x0000005A ntdll!RtlAllocateHeap+0x00000808 MyApp!_heap_alloc_base+0x00000069 MyApp!_heap_alloc_dbg+0x000001A2 MyApp!_nh_malloc_dbg+0x00000023 MyApp!_nh_malloc+0x00000016 MyApp!operator new+0x0000000E MyApp!DisplayMyGraphics+0x0000001E MyApp!main+0x0000002C MyApp!mainCRTStartup+0x000000FC KERNEL32!BaseProcessStart+0x0000003D
此 UMDH 輸出會顯示從呼叫堆疊配置的總位元組數0x5320 (十進位 21280) 。 這些位元組是從0x14 (十進位 20 配置,) 個別配置0x428 (十進位 1064) 個位元組。
呼叫堆疊的識別碼為 「BackTrace00B53」,而且會顯示此堆疊中的呼叫。 在檢閱呼叫堆疊時,您會看到 DisplayMyGraphics 常式是透過 新的 運算子配置記憶體,它會呼叫常式 malloc,它會使用 Visual C++ 執行時間程式庫從堆積取得記憶體。
判斷這些呼叫中的哪一個是最後一個呼叫,以明確出現在您的原始程式碼中。 在此情況下,可能是 新的 運算子,因為 對 malloc 的呼叫是在 新的 實作中發生,而不是作為個別的配置。 因此,DisplayMyGraphics常式中的這個新運算子實例會重複配置未釋放的記憶體。