Using the Kernel Debugger to Find a Kernel-Mode Memory Leak
The kernel debugger determines the precise location of a kernel-mode memory leak.
Enable Pool Tagging
You must first use GFlags to enable pool tagging. GFlags is included in Debugging Tools for Windows. Start GFlags, choose the System Registry tab, check the Enable Pool Tagging box, and then select Apply. You must restart Windows for this setting to take effect.
On Windows Server 2003 and later versions of Windows, pool tagging is always enabled.
Determining the Pool Tag of the Leak
To determine which pool tag is associated with the leak, it is usually easiest to use the PoolMon tool for this step. For details, see Using PoolMon to Find Kernel-Mode Memory Leaks.
Alternatively, you can use the kernel debugger to look for tags associated with large pool allocations. To do so, follow this procedure:
Reload all modules by using the .reload (Reload Module) command.
Use the !poolused extension. Include the flag "4" to sort the output by paged memory use:
kd> !poolused 4 Sorting by Paged Pool Consumed Pool Used: NonPaged Paged Tag Allocs Used Allocs Used Abc 0 0 36405 33930272 Tron 0 0 552 7863232 IoN7 0 0 10939 998432 Gla5 1 128 2222 924352 Ggb 0 0 22 828384
Determine which pool tag is associated with the greatest usage of memory. In this example, the driver using the tag "Abc" is using the most memory--almost 34 MB. Therefore, the memory leak is most likely to be in this driver.
Finding the Leak
After you have determined the pool tag associated with the leak, follow this procedure to locate the leak itself:
Use the ed (Enter Values) command to modify the value of the global system variable PoolHitTag. This global variable causes the debugger to break whenever a pool tag matching its value is used.
Set PoolHitTag equal to the tag that you suspect to be the source of the memory leak. The module name "nt" should be specified for faster symbol resolution. The tag value must be entered in little-endian format (that is, backward). Because pool tags are always four characters, this tag is actually A-b-c-space, not merely A-b-c. So use the following command:
kd> ed nt!poolhittag ' cbA'
To verify the current value of PoolHitTag, use the db (Display Memory) command:
kd> db nt!poolhittag L4 820f2ba4 41 62 63 20 Abc
The debugger will break every time that pool is allocated or freed with the tag Abc. Each time the debugger breaks on one of these allocations or free operations, use the kb (Display Stack Backtrace) debugger command to view the stack trace.
Using this procedure, you can determine which code resident in memory is overallocating pool with the tag Abc.
To clear the breakpoint, set PoolHitTag to zero:
kd> ed nt!poolhittag 0
If there are several different places where memory with this tag is being allocated and these are in an application or driver that you have written, you can alter your source code to use unique tags for each of these allocations.
If you cannot recompile the program but you want to determine which one of several possible locations in the code is causing the leak, you can unassemble the code at each location and use the debugger to edit this code resident in memory so that each instance uses a distinct (and previously unused) pool tag. Then allow the system to run for several minutes or more. After some time has passed, break in again with the debugger and use the !poolfind extension to find all pool allocations associated with each of the new tags.