How do I diagnose a Handle leak?
Asked Answered
I

2

13

I've got a process that is hosting a WCF ServiceHost. It leaks handles like crazy according to ProcessExplorer. I've gone over the code and can't find anything obvious that's causing leaked handles.

The closest I can come to is the listing of handles provided by ProcessExplorer, but the usefulness of that seems limited. Are there any other tools out there to help diagnose where a handle came from, like via a stack trace or something?

EDIT

I've got the Windbg installed. When I use it to list handles, it's showing me that 914 handles are of type "Event" -

If I pick a few of these, and output using !handle x f I get output similar to this on most:

Type           Event
Attributes     0 
GrantedAccess  0x1f0003
HandleCount    2
PointerCount   3
Object Specific Information
    Event Type Manual Reset
    Event is Set

Is there a way to dig in further to determine more about the event?

Imine answered 1/10, 2011 at 0:11 Comment(3)
Visual Studio Code Analysis (or FxCop) will tell you if you are failing to properly Dispose of resources.Anthropo
John, I'm curious, why did you post your answer as a comment and not an answer?Bufflehead
Didn't think it was much of an answer. I hoped someone else would do a better job with the idea.Anthropo
M
17

Sorry for the earlier bad answer (now deleted, it appears).

The Debugging Tools for Windows package includes WinDbg and friends. WindDbg is a full debugger like Visual Studio, but leaner and meaner, and more capable in many ways. Run WinDbg, attach to your process (F6), and type !handle in the command window. You'll get a list of all the handles and some statistics. If you scroll up and see a handle that looks like it might be one of the leaky ones, you can do !handle <handlenum> f to show more information about it. For example, attaching to iexplore.exe on my system:

0:019> !handle 1bc f
Handle 1bc
  Type          Key
  Attributes    0
  GrantedAccess 0x2001f:
         ReadControl
         QueryValue,SetValue,CreateSubKey,EnumSubKey,Notify
  HandleCount   2
  PointerCount  3
  Name          \REGISTRY\USER\S-1-5-21-498032705-2416727736-2837886327-1001\Software\Microsoft\Windows\CurrentVersion\Internet Settings
  Object Specific Information
    Key last write time:  11:04:51. 9/4/2011
    Key name Internet Settings

EDIT

To find out more information, you can use the !htrace windbg command. To use it, attach to your process using windbg, and type !htrace -enable, then type g to resume the process. Exercise the process for a bit, and then break in using CTRL-Break (i.e. CTRL-Pause). Type !htrace -diff. You should see a list of stack traces showing open handles and the call stack at the time they were opened. If you don't have Windows symbols set up, the only addresses that will make sense will be your own code -- but that should be plenty to get you the clues you need.

<snip>
ModLoad: 00000000`75020000 00000000`7504d000   WINTRUST.dll
ModLoad: 00000000`75160000 00000000`7527d000   CRYPT32.dll
ModLoad: 00000000`757d0000 00000000`757dc000   MSASN1.dll
(2fd0.1ce4): Break instruction exception - code 80000003 (first chance)
ntdll!DbgBreakPoint:
00000000`77440530 cc              int     3
0:019> !htrace -enable
Handle tracing enabled.
Handle tracing information snapshot successfully taken.
0:019> g
(2fd0.2c88): Break instruction exception - code 80000003 (first chance)
ntdll!DbgBreakPoint:
00000000`77440530 cc              int     3
0:019> !htrace -diff
Handle tracing information snapshot successfully taken.
0x360 new stack traces since the previous snapshot.
Ignoring handles that were already closed...
Outstanding handles opened since the previous snapshot:
--------------------------------------
Handle = 0x000000000000070c - OPEN
Thread ID = 0x0000000000000c44, Process ID = 0x0000000000002fd0

0x000000007744232a: ntdll!NtOpenThread+0x000000000000000a
0x0000000074c83910: wow64!whNtOpenThread+0x00000000000000a0
0x0000000074c6cf87: wow64!Wow64SystemServiceEx+0x00000000000000d7
0x0000000074bf2776: wow64cpu!TurboDispatchJumpAddressEnd+0x000000000000002d
0x0000000074c6d07e: wow64!RunCpuSimulation+0x000000000000000a
0x0000000074c6c549: wow64!Wow64LdrpInitialize+0x0000000000000429
0x000000007746e707: ntdll! ?? ::FNODOBFM::`string'+0x0000000000029364
0x000000007741c32e: ntdll!LdrInitializeThunk+0x000000000000000e
0x00000000775f113a: ntdll_775d0000!ZwOpenThread+0x0000000000000012
0x0000000075ea2e32: KERNELBASE!OpenThread+0x0000000000000049
0x00000000755578df: iertutil!CIsoMalloc::AllocArtifact+0x0000000000000050
0x00000000755578b4:  iertutil!CIntraprocessMessageQueueSite::_QueryMessageThreadAffinityHelper_UntrustedSerializedIsoMessage+0x0000000000000055
0x0000000075557754: iertutil!CIntraprocessMessageQueueSite::QueryMessageThreadAffinity+0x000000000000004b
--------------------------------------
Handle = 0x0000000000000790 - OPEN
Thread ID = 0x00000000000019d4, Process ID = 0x0000000000002fd0

0x000000007744226a: ntdll!NtOpenKeyEx+0x000000000000000a
0x0000000074c8d205: wow64!Wow64NtOpenKey+0x0000000000000091
0x0000000074c8314f: wow64!whNtOpenKeyEx+0x0000000000000073
0x0000000074c6cf87: wow64!Wow64SystemServiceEx+0x00000000000000d7
0x0000000074bf2776: wow64cpu!TurboDispatchJumpAddressEnd+0x000000000000002d
0x0000000074c6d07e: wow64!RunCpuSimulation+0x000000000000000a
0x0000000074c6c549: wow64!Wow64LdrpInitialize+0x0000000000000429
0x000000007746e707: ntdll! ?? ::FNODOBFM::`string'+0x0000000000029364
0x000000007741c32e: ntdll!LdrInitializeThunk+0x000000000000000e
0x00000000775f101a: ntdll_775d0000!ZwOpenKeyEx+0x0000000000000012
0x0000000075ad2271: KERNEL32!LocalBaseRegOpenKey+0x000000000000010c
0x0000000075ad2416: KERNEL32!RegOpenKeyExInternalW+0x0000000000000130
0x0000000075ad2302: KERNEL32!RegOpenKeyExW+0x0000000000000021
--------------------------------------
Handle = 0x0000000000000788 - OPEN
Thread ID = 0x00000000000019d4, Process ID = 0x0000000000002fd0

0x000000007744226a: ntdll!NtOpenKeyEx+0x000000000000000a
0x0000000074c8d205: wow64!Wow64NtOpenKey+0x0000000000000091
0x0000000074c8314f: wow64!whNtOpenKeyEx+0x0000000000000073
0x0000000074c6cf87: wow64!Wow64SystemServiceEx+0x00000000000000d7
0x0000000074bf2776: wow64cpu!TurboDispatchJumpAddressEnd+0x000000000000002d
0x0000000074c6d07e: wow64!RunCpuSimulation+0x000000000000000a
0x0000000074c6c549: wow64!Wow64LdrpInitialize+0x0000000000000429
0x000000007746e707: ntdll! ?? ::FNODOBFM::`string'+0x0000000000029364
0x000000007741c32e: ntdll!LdrInitializeThunk+0x000000000000000e
0x00000000775f101a: ntdll_775d0000!ZwOpenKeyEx+0x0000000000000012
0x0000000075ad2271: KERNEL32!LocalBaseRegOpenKey+0x000000000000010c
0x0000000075ad2416: KERNEL32!RegOpenKeyExInternalW+0x0000000000000130
0x0000000075ad2302: KERNEL32!RegOpenKeyExW+0x0000000000000021
<snip>
Matthaeus answered 1/10, 2011 at 3:39 Comment(2)
Dumb question... I found what I thought was the Debugging tools for windows package, but after install, there is no mention of WinDbg - where do I install from officially to get it?Imine
Got it, had to install the 64 bit version before it would install the Debugging tools.Imine
E
1

Use a memory profiler - they can help to find such leaks, for example:

Erasure answered 3/10, 2011 at 22:28 Comment(1)
I use both RedGate Memory Profiler and SciTech Memory Profiler. When I need to step into power user mode, I switch to SciTech (memprofiler.com).Nelia

© 2022 - 2024 — McMap. All rights reserved.