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