NetInverse Developers Blog

April 11, 2009
Category: Debugging — Tags: , , , , — admin @ 8:30 pm

SOS Command: !GCHandles [-perdomain]

!GCHandles provides statistics about GCHandles in the process. Sometimes the source of a memory leak is a GCHandle leak. For example, code might keep a 50 Megabyte array alive because a strong GCHandle points to it, and the handle was discarded without freeing it.

The most common handles are “Strong Handles,” which keep the object they point to alive until the handle is explicitly freed. “Pinned Handles” are used to prevent the garbage collector from moving an object during collection. These should be used sparingly, and for short periods of time. If you don’t follow that precept, the gc heap can become very fragmented.

If you run with the -perdomain option, you will get the same output broken down by AppDomain. Here is sample output from a very simple program:

!GCHandles
GC Handle Statistics:
Strong Handles: 15
Pinned Handles: 4
Async Pinned Handles: 0
Ref Count Handles: 0
Weak Long Handles: 0
Weak Short Handles: 1
Other Handles: 0
Statistics:
      MT    Count    TotalSize Class Name
7933061c        1           12 System.Object
793310cc        1           28 System.SharedStatics
79331f4c        2           48 System.Reflection.Assembly
79330d44        1           72 System.ExecutionEngineException
79330cb4        1           72 System.StackOverflowException
79330c24        1           72 System.OutOfMemoryException
793311e0        1          100 System.AppDomain
79330fd4        2          112 System.Threading.Thread
793326c4        4          144 System.Security.PermissionSet
79330dd4        2          144 System.Threading.ThreadAbortException
793041d0        4         8736 System.Object[]
Total 20 objects

See also: !GCHandleLeaks

This command is an aid in tracking down GCHandle leaks. It searches all of memory for any references to the Strong and Pinned GCHandles in the process, and reports what it found. If a handle is found, you’ll see the address of the reference. This might be a stack address or a field within an object, for example. If a handle is not found in memory, you’ll get notification of that too.

The command has diagnostic output which doesn’t need to be repeated here. One thing to keep in mind is that anytime you search all of memory for a value, you can get false positives because even though the value was found, it might be garbage in that no code knows about the address. You can also get false negatives because a user is free to pass that GCHandle to unmanaged code that might store the handle in a strange way (shifting bits, for example). For example, a GCHandle valuetype is stored on the stack with the low bit set if it points to a Pinned handle. So !GCHandleLeaks ignores the low bit in it’s searches.

That said, if a serious leak is going on, you’ll get a ever-growing set of handle addresses that couldn’t be found.

!gchandleleaks
-------------------------------------------------------------------------------
GCHandleLeaks will report any GCHandles that couldn't be found in memory.
Strong and Pinned GCHandles are reported at this time. You can safely abort the
memory scan with Control-C or Control-Break.
-------------------------------------------------------------------------------
Found 19 handles:
009111a8	009111ac	009111b4	009111bc
009111c0	009111cc	009111d0	009111d4
009111d8	009111dc	009111e0	009111e4
009111e8	009111f8	009111fc	009113f0
009113f4	009113f8	009113fc
Searching memory
Reference found in stress log will be ignored
Error during command: Warning. Extension is using a callback which Visual Studio does not implement.

------------------------------------------------------------------------------
Some handles were not found. If the number of not-found handles grows over the
lifetime of your application, you may have a GCHandle leak. This will cause
the GC Heap to grow larger as objects are being kept alive, referenced only
by the orphaned handle. If the number doesn't grow over time, note that there
may be some noise in this output, as an unmanaged application may be storing
the handle in a non-standard way, perhaps with some bits flipped. The memory
scan wouldn't be able to find those.
------------------------------------------------------------------------------
Didn't find 19 handles:
009111a8	009111ac	009111b4	009111bc
009111c0	009111cc	009111d0	009111d4
009111d8	009111dc	009111e0	009111e4
009111e8	009111f8	009111fc	009113f0
009113f4	009113f8	009113fc

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

©2009 NetInverse. All rights reserved. Powered by WordPress