Microsoft KB Archive/268343

From BetaArchive Wiki

Article ID: 268343

Article Last Modified on 4/25/2007



APPLIES TO

  • Microsoft Windows 2000 Server
  • Microsoft Windows 2000 Advanced Server
  • Microsoft Windows 2000 Professional Edition
  • Microsoft Windows NT Server 4.0 Standard Edition
  • Microsoft Windows NT Workstation 4.0 Developer Edition



This article was previously published under Q268343

SUMMARY

The user-mode dump heap (UMDH) utility works with the operating system to analyze Windows heap allocations for a specific process. This utility, and the other tools associated with it, are primarily targeted for Windows 2000 and Windows XP. Click the Play button to view this streaming media demonstration.
Note Because the malloc function in the C run-time (CRT) module uses the frame pointer omission (FPO) on the original release version of Windows Server 2003, you may not see the complete stack information of the malloc function by using the UMDH tool. This issue is fixed in the CRT module of Windows Server 2003 Service Pack 1 (SP1). Therefore, you can see the complete stack information of the malloc function in Windows Server 2003 SP1.

MORE INFORMATION

Before You Use UMDH

If you think that you are experiencing a memory leak, be aware that memory leaks may not be what they appear to be. You may discover that a memory leak is not a true memory leak, but is a performance enhancement. For example, the Microsoft Jet database engine can consume large amounts of memory (up to 128 MB on a 256-MB computer) because it retrieves data and writes caches. The cache permits the Jet engine to get fast read-ahead and write-ahead buffering.

To determine whether or not a process is experiencing memory leaks, use Windows Performance Monitor (Perfmon.exe) and monitor Private Bytes under the Process category for your application. Private bytes is the total memory that the process has allocated, but is not sharing with other processes. Note that this is different from Virtual Bytes, which is also interesting to monitor. Virtual Bytes is the current size in bytes of the virtual address space that the process uses. An application can leak virtual memory, but may not see a difference in the private bytes that are allocated. If you do not see memory increase when you monitor private bytes, but you suspect that you are still running out of memory, monitor virtual bytes to see if you are using up virtual memory. For additional information about detecting memory leaks and the overview of Windows Performance Monitor (Perfmon.exe), visit the following Microsoft Web site:

To make sure that your application is leaking memory, put the suspect code in a loop with many iterations, and then monitor private and virtual bytes for any increases of memory. Watch to make sure that the number of private bytes and virtual bytes does not eventually stay the same and the number stops increasing. If there is a point at which the memory stops increasing, (for example, it does not continue to climb indefinitely) you do not see a memory leak but more likely, you see a cache that is growing to its maximum size.

If you determine that you see a memory leak, before you use UMDH, follow these steps:

  1. Install the UMDH utility.
  2. Set the System PATH environment variable to include the folder where you installed UMDH.
  3. Set the _NT_SYMBOL_PATH environment variable to the Microsoft symbol server path so that UMDH can locate debug symbol files.

The UMDH utility is included with the Debugging Tools for Windows products at the following Microsoft Web site:

Download and install the utility, and then set the PATH system environment variable to the path where the debugging tools were installed.

Before you use UMDH, you must install the correct debug symbols for the components of your application and your operating system. Use the Microsoft Symbol Server to acquire debug symbols for Microsoft components. For more information about the Microsoft Symbol Server, click the following article number to view the article in the Microsoft Knowledge Base:

311503 Use the Microsoft Symbol Server to obtain debug symbol files


UMDH tries to find the symbol files by using the _NT_SYMBOL_PATH environment variable. The command to set the path from a command prompt might look similar to the following:

set _NT_SYMBOL_PATH=SRV*c:\LocalSymbolCache


For additional information about setting up symbolic debugging information, see the "Debug Symbols" section later in this article.

After you complete these steps, you are ready to use the UMDH utility.

Capturing Heap Dumps with UMDH

UMDH is a utility that dumps information about the heap allocations of a process. This information includes the callstack for each allocation, the number of allocations that are made through that callstack, and the number of bytes that are consumed through that callstack. For example:

00005320 bytes in 0x14 allocations (@ 0x00000428) by: BackTrace00053
           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!LeakyFunc+0x0000001E
           MyApp!main+0x0000002C
           MyApp!mainCRTStartup+0x000000FC
           KERNEL32!BaseProcessStart+0x0000003D
                

This UMDH output shows that there were 21280 (0x5320) bytes allocated total from the callstack. The 21280 bytes were allocated from 20 (0x14) separate allocations of 1064 bytes (0x428). The callstack is given an identifier of BackTrace00053.

To produce a dump file of the heap allocations, you must use the Gflags.exe utility, which is also included with the Debugging Tools for Windows products, to let the operating system know that you want the kernel to track the allocations.

Assume that you want to dump the heap(s) contents for Notepad.exe. First you must enable stack trace acquisition for the application that you want to test. By default, this feature is not enabled. The command to enable this feature is as follows:

gflags -i notepad.exe +ust


The command does not enable stack tracing for processes that are already running, but it enables stack tracing for all future executions of Notepad.exe. Alternatively, you can set the flag through the GFLAGS user interface (run Gflags.exe without any arguments to get the user interface). Use the -ust option for gflags to disable the stack tracing when you are finished debugging.

When you set the image flags through Gflags.exe, and you set up the debug symbols, you are ready to start Notepad (the application that is using UMDH). After the program is started, you must determine the Process ID (PID) of the Notepad process that was just started. The command for this is as follows:

tlist


You can find the PID from the output of the TLIST application. The PID information can also be obtained from Task Manager. Assume the PID for the Notepad process that you just started is 124. You can use UMDH to get a heap dump with the following command:

umdh -p:124 -f:notepad124.log


Results: You have a complete heap dump of the Notepad process in the Notepad124.log file. This file shows all of the allocations that were made and the callstacks where the allocations were made.

Use Umdh.exe to Compare UMDH Logs

While the UMDH log file contains valuable information about the current state of the heaps for a process, if you are concerned with finding a memory leak, it may be more valuable to compare the outputs of two logs and find out what callstack has seen the largest growth between the two dump files. The Umdh.exe utility helps compare two UMDH logs to provide an analysis of the difference between them. Once you have two logs captured at different intervals, you can then use the following command:

UMDH dh1.log dh2.log > cmp12.txt


-or-

UMDH -d dh1.log dh2.log > cmp12.txt


The -d command line option tells UMDH to display in decimal instead of hexadecimal. The output of the command compares the differences of the allocations between the two logs and provides information that is similar to the following:

+ 5320 ( f110 - 9df0) 3a allocs BackTrace00053 Total increase == 5320


For each BackTrace in the UMDH log files, there is a comparison made between the two logs files. This case shows that the last log file that is specified in the UMDH command line had 0xF110 bytes allocated while the first log in the UMDH command line had 0x9DF0 bytes allocated for the same BackTrace (callstack). The "5320" is the difference in the number of bytes allocated. In this case, there were 0x5320 more bytes allocated between the times that the two logs were captured. The bytes came from the callstack that is identified by "BackTrace00053".

The next step is to find out what is in that backtrace. If you open the second log file and search for BackTrace00053, you may find something that similar to the following:

00005320 bytes in 0x14 allocations (@ 0x00000428) by: BackTrace00053
           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!LeakyFunc+0x0000001E
           MyApp!main+0x0000002C
           MyApp!mainCRTStartup+0x000000FC
           KERNEL32!BaseProcessStart+0x0000003D
                

When you view the callstack, you can see that the LeakyFunc function allocates memory through the Visual C++ run-time library operator new function. If you find that the number of allocations grows as you take more dump files, you may conclude that memory is not being freed.

Enabling Stack Traces

The most important information in UMDH logs is the stack traces of the heap allocations. You can analyze them to verify if a process leaks heap memory. By default, these stack traces are not acquired. You can enable this feature per-process or system-wide. Use the following command to enable stack tracing system-wide:

gflags -r +ust


Restart the computer after this command. For per-process enabling, the command is as follows:

gflags -i APPNAME +ust


Where APPNAME is the file name of the executable including the extension (For example, Services.exe, Lsass.exe). The command does not enable stack tracing for a process that is already running. Therefore, for processes that you cannot restart (for example, services, lsass, winlogon), you must restart your test computer.

Use the following commands to verify what settings have been set system-wide or for a specific process: System-wide:

gflags -r


Specific process:

gflags -i APP-NAME


By default, the maximum stack trace depth is 16. If you want to see deeper callstacks, you can increase this by running GFLAGS. Click to select System Registry, and then type a new depth in the Max. Stack Trace Capture Depth edit control. Click Apply, and then restart the computer.
IMPORTANT: If you are using Windows NT 4.0 Service Pack 6, you must use Umdh_nt4.exe, instead of Umdh.exe, and you must use the gflags -r command to set system-wide stack tracing. Make sure that you restart your computer. Umdh_nt4 stack tracing does not work on a per process basis on Windows NT version 4. It must be set for the whole system.

Debug Symbols

One of the most important steps to using UMDH is to make sure that you have good symbol files (.dbg or .pdb file) to get a good stack trace. At a minimum, you need the Kernel32.dbg and Ntdll.dbg symbol files. You can acquire additional debugging symbols that you may need as you find out more about which components leak memory. For more information about how to get debug symbol files for Microsoft components, click the following article number to view the article in the Microsoft Knowledge Base:

311503 Use the Microsoft Symbol Server to obtain debug symbol files


For additional information about how to use the Microsoft Symbol Server and how to obtain Windows symbol packages, visit the following Microsoft Web site:

When you build components with Visual C++, it is important that you not have Program Database for Edit and Continue selected for the C++ compiler options. Instead, select Program Database. To set the symbol path, initialize the _NT_SYMBOL_PATH environment variable to the path to be used. You can use the Microsoft Symbol Server to acquire symbols for Microsoft components.

311503 Use the Microsoft Symbol Server to obtain debug symbol files


Follow these steps to set the _NT_SYMBOL_PATH environment variable:

  1. In Control Panel, double-click System.
  2. Click the Advanced tab, and then click Environmental Variables.

Or you can set the _NT_SYMBOL_PATH environment variable in a command window before UMDH is run.

NOTE: Also include the path to the PDBs for the components of your application. For example, set the path for _NT_SYMBOL_PATH to the following:

The first part of this path points to the Microsoft Symbol Server and states that the symbols that are used will be downloaded in the c:\symbols folder. The part that follows the semi-colon is the path to the PDB files (symbol files) specifically for the leaking application.

Invoking UMDH

The only required command-line parameter for UMDH is the -p option, which specifies the PID of the process from which a heap dump will be obtained. The PID can be obtained by using Task Manager or the Tlist.exe program. For a command similar to the following, the log will be dumped to the standard output:

umdh -p:PID


UMDH also displays various informational messages to standard error, and therefore if you do not redirect it, it is mixed with the real log. To gather the UMDH informational messages in a file, use the following command:

umdh -p:PID 2>umdh.msg


If you want to gather the log that is dumped by UMDH in a file, use one of the following commands:

umdh -p:PID >umdh.log


-or-

umdh -p:PID -f:umdh.log


These commands are equivalent.

The default log that is obtained by UMDH contains an enumeration of heap consumers that are sorted by allocation count. If, for debugging purposes, you also need a dump file of all of the allocated blocks with their corresponding stack traces, the -d option can be used:

umdh -p:PID -d


If you use this command, you might see the following in the UMDH log file:

Allocations for trace BackTrace00046: 005F69A0 005F6150

These are the memory addresses of the allocations for that callstack. If your debugger is attached to the process, you can dump the contents of the memory at these addresses to see what has been allocated.

If the log contains too much information, it can be limited only to big users who have the allocation count above a certain threshold. Use the following command:

umdh -p:PID -t:THRESHOLD


All of the command-line options (for example, -p, -f, -t, -d) can be specified simultaneously in any order. The following is a more difficult command-line example:

umdh -p:123 -t:1000 -f:umdh.log -d


This command dumps the heaps for the process with PID 123 into the Umdh.log file. It dumps only stack traces that account for more than 1000 allocations and it also dumps the addresses of the heap blocks that are allocated through each stack trace.

Another useful UMDH option is the -l option. This causes file and line numbers to be printed in the callstack whenever possible.

UMDH Output Explained

If you redirected the log to a file (umdh -p:PID -f:umdh.log), the contents are similar to the following, which was obtained from a running Notepad process:

UMDH: Logtime 2000-06-28 10:54 - Machine=MYMachine - PID=704
   *********** Heap 00270000 Information ********************
       Flags: 58000062
       Number Of Entries: 87
       Number Of Tags: <unknown>
       Bytes Allocated: 00008DF0
       Bytes Committed: 0000A000
       Total FreeSpace: 00001210
       Number of Virtual Address chunks used: 1
       Address Space Used: <unknown>
       Entry Overhead: 8
       Creator:  (Backtrace00007)
           ntdll!RtlDebugCreateHeap+0x00000196
           ntdll!RtlCreateHeap+0x0000023F
           ntdll!LdrpInitializeProcess+0x00000369
           ntdll!LdrpInitialize+0x0000028D
           ntdll!KiUserApcDispatcher+0x00000007
   *********** Heap 00270000 Hogs ********************
   000001A0 bytes in 0x4 allocations (@ 0x00000068) by: BackTrace00031
           ntdll!RtlDebugAllocateHeap+0x000000FB
           ntdll!RtlAllocateHeapSlowly+0x0000005B
           ntdll!RtlAllocateHeap+0x00000D81
           ntdll!LdrpAllocateDataTableEntry+0x00000039
           ntdll!LdrpMapDll+0x000002A4
           ntdll!LdrpLoadImportModule+0x0000010D
           ntdll!LdrpWalkImportDescriptor+0x0000008B
           ntdll!LdrpLoadImportModule+0x0000011D
           ntdll!LdrpWalkImportDescriptor+0x0000008B
           ntdll!LdrpLoadImportModule+0x0000011D
           ntdll!LdrpWalkImportDescriptor+0x0000008B
           ntdll!LdrpInitializeProcess+0x000009DC
           ntdll!LdrpInitialize+0x0000028D
           ntdll!KiUserApcDispatcher+0x00000007

   000001A0 bytes in 0x4 allocations (@ 0x00000068) by: BackTrace00034
           ntdll!RtlDebugAllocateHeap+0x000000FB
           ntdll!RtlAllocateHeapSlowly+0x0000005B
           ntdll!RtlAllocateHeap+0x00000D81
           ntdll!LdrpAllocateDataTableEntry+0x00000039
           ntdll!LdrpMapDll+0x000002A4
           ntdll!LdrpLoadImportModule+0x0000010D
           ntdll!LdrpWalkImportDescriptor+0x0000008B
           ntdll!LdrpLoadImportModule+0x0000011D
           ntdll!LdrpWalkImportDescriptor+0x0000008B
           ntdll!LdrpLoadImportModule+0x0000011D
           ntdll!LdrpWalkImportDescriptor+0x0000008B
           ntdll!LdrpLoadImportModule+0x0000011D
           ntdll!LdrpWalkImportDescriptor+0x0000008B
           ntdll!LdrpInitializeProcess+0x000009DC
           ntdll!LdrpInitialize+0x0000028D
           ntdll!KiUserApcDispatcher+0x00000007
                

The log contains a dump of every heap in the process. In this example, the log starts with a heap at address 270000. After a few global counters for the heap, the log contains a dump in decreasing sorted order of stack traces that are responsible for the most allocations. When you compare the dynamics of memory that are used at different moments, you can deduce what occurred in the process and if any heap use is similar to a leak.

Problems That You Can Experience When You Use UMDH

The most common errors when you use UMDH occur because stack tracing is not enabled. Also, incorrect symbols for Ntdll.dll prevent UMDH from running. For the other symbols files, UMDH runs but the log file contains stack traces that do not have function names but instead have relative addresses inside modules. A distant third error is specifying a wrong PID. The following error message results when you try to run UMDH for a process that does not have stack tracing enabled:

C:\>umdh -p:1140 UMDH: Logtime 2000-06-28 12:43 - Machine=MyMachine - PID=1140 Connecting.....Module enumeration complete. SymGetSymFromName(process, ntdll!RtlpStackTraceDataBase, xxx) failed, LastError = 126 UmdhGetAddrFromName couldn't find Stack Trace DB pointer (ntdll!RtlpStackTraceDataBase). ntdll.dll symbols are incorrect; we must be able to see non-import symbols.

Use the following command to double-check the settings for the process that you are investigating:

gflags -i APPNAME


Use the following command when you rely on system-wide stack tracing:

gflags -r


These commands show the list of flags set for the application. Note that in the case of system-wide stack tracing, the feature might appear as active but if you did not restart the computer after running the gflags -r +ust command, it is not actually activated. If you want to know every application that has stack tracing enabled, you can view the USTEnabled key under the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options


If you run UMDH on a process that has stack tracing enabled, but you have not restarted the application since you set the flags, you may receive the following message in your logs:

A stack trace was not saved for this allocation (Index == 0)

If you run do not set the correct symbol path or the symbols are incorrect, and you run UMDH, you may receive an error message in the log. However, you may only receive incorrect or misleading callstacks. To verify that you have the correct symbols, start the NTSD system debugger for a process, for example:

ntsd notepad


Then, from the debugger console, run the LD command to load the symbol information for the module and the LM command to list what modules have their symbols loaded. If the output of the LM command shows export symbols loaded, the symbols are not good. If you have PDB symbols loaded, the symbols are good. You may receive the following error message if you specified the wrong PID:

C:\>umdh -p:1000 UMDH: Logtime 2000-06-28 09:45 - Machine=MyMachine - PID=1000 Connecting... OpenProcess failed, LastError = 0x57

Call UMDH from Visual Basic

It may be useful sometimes to dump a number of logs over time because the leak may not be very noticeable at first. For example, if you suspect that your Active Server Pages (ASP) Web application is leaking memory, it may be helpful to write a COM component in Visual Basic that shells out to UMDH. You can then call that component from your ASP page.

The following is some Visual Basic code that invokes UMDH and creates a log file that is based on the current time:

Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
      Public Function GetProcessID()
      GetProcessID = GetCurrentProcessId()
      End Function  
   .
   .
   .
      Dim strTime As String

      Dim sProcID As String
      sProcID = GetProcessID()
      strTime = "MYLOG_" & Format(Now(), "hhmm")
     
      Shell ("C:\UMDH\umdh -p:" & sProcID & " -f:d:\logs\" & strTime & ".txt")
                

Use UMDH with Windows NT 4.0 Service Pack 6a (SP6a)

The UMDH utility that is included with the Debugging Tools for Windows products does not work on Windows NT 4.0. A self-extracting executable (Umdhnt4tools.exe) is included with this article and contains the following tools to be used with NT 4.0:

  • Umdh_nt4.exe and Dbghelp.dll

This is the Windows NT 4.0 SP6 version of the UMDH utility.

  • Dhcmp.exe

This utility is used to compare two UMDH dumps to determine where a possible memory leak occurrs.

The following file is available for download from the Microsoft Download Center:

Release Date: August 28, 2002

For more information about how to download Microsoft support files, click the following article number to view the article in the Microsoft Knowledge Base:

119591 How to obtain Microsoft support files from online services


Microsoft scanned this file for viruses. Microsoft used the most current virus-detection software that was available on the date that the file was posted. The file is stored on security-enhanced servers that help prevent any unauthorized changes to the file. Put Umdh_nt4.exe and Dbghelp.dll in a folder, and then put them first in your PATH environment variable. Use Umdh_nt4.exe instead of UMDH.

On a computer that is running Windows NT 4.0, you must use Gflags.exe to set system-wide stack tracing. For example:

gflags -r


Make sure that you restart your computer. Umdh_nt4 stack tracing does not work on a per-process basis on Windows NT version 4.0. It is set for the whole system.

UMDH_NT4 is unlike UMDH in that it does not compare log files. For example, you cannot do the following:

UMDH_NT4 dh1.log dh2.log > cmp12.txt


Instead you must use the Dhcmp.exe utility that is included with this article. The command looks similar to the following:

DHCMP dh1.log dh2.log > cmp12.txt



Additional query words: DH umDHtools dumpheap displayheap DSDebugTools

Keywords: kbdownload kbarttypeshowme kbfile kbgraphxlinkcritical kbhowto kbsample KB268343