How can I discover what finalizable objects are in the generation 0 heap?
Asked Answered
H

3

10

I am trying to track down a performance issue related to garbage collection, and one symptom is that the "Promoted Finalization-Memory from Gen0" counter shows a very large number of objects with finalizers are being created and making their way out of Gen 0 after each Gen0 collection.

How can I discover what these objects are?

Hewitt answered 20/8, 2014 at 18:14 Comment(1)
How? Profile. jetbrains.com/dotmemoryEnrichment
G
4

Another way to do this is with the finalizequeue command provided by SOS. This shows all objects registered for finalization, not just those that are ready for finalization:

0:010> !finalizequeue
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 33 finalizable objects (000000001b2b9710->000000001b2b9818)
generation 1 has 2 finalizable objects (000000001b2b9700->000000001b2b9710)
generation 2 has 580 finalizable objects (000000001b2b84e0->000000001b2b9700)
Ready for finalization 0 objects (000000001b2b9818->000000001b2b9818)
Statistics for all finalizable objects (including all objects ready for finalization):
              MT    Count    TotalSize Class Name
000007feebb95cb8        1           24 System.Threading.OverlappedDataCache
000007feebb81168        1           24 System.LocalDataStoreHolder
000007feebb14630        1           24 System.Threading.TimerHolder
000007feebb63a38        1           32 Microsoft.Win32.SafeHandles.SafePEFileHandle
000007feebb5ae38        1           32 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
000007feebb5ada8        1           32 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
...<snip>...
Total 615 objects

Then you can dump all objects in the generation 1 range of memory (clipping off the end since it won't be inclusive). I only have two in generation 1 here, fortunately:

0:010> dd 000000001b2b9700 000000001b2b9710-4
00000000`1b2b9700  02d51da0 00000000 02d51d50 00000000

Then dump those objects out (this is just the first one):

0:010> !do 02d51da0 
Name:        System.WeakReference
MethodTable: 000007feebb6cbb0
EEClass:     000007feeb53f1d8
Size:        24(0x18) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feebb6a338  4000688        8        System.IntPtr  1 instance           2128d8 m_handle
Gaslit answered 20/8, 2014 at 20:12 Comment(0)
G
6

You can use WinDbg, with the SOS extension to find out what objects are living in Gen 0.

Attach WinDbg to your .NET app and load SOS - here's a handy tip, found here:

http://www.wintellect.com/blogs/jrobbins/automatically-load-the-right-sos-for-the-minidump

Basically type the following command:

!analyze –v

This should download the correct SOS.DLL file for you. If that fails you can run these two commands:

.loadby sos clr

or

.loadby sos mscorwks

I forget which one should work (I think you need the first one if the .NET app is .NET 4.0 and above), but try both. Next, try the following command !dumpheap:

!dumpheap -gen 0

This should show you a listing of all the objects in Gen 0. This hopefully will help you.

EDIT:

Here's a YouTube video showing how to use WinDbg to debug .NET apps:

https://www.youtube.com/watch?v=yVzNrz1jJHU

Gaven answered 20/8, 2014 at 18:48 Comment(2)
Any chance you would know why the -gen option isn't available in my WinDbg environment? The help option shows how to get the contents of the gen0 heap using a combination of !EEHeap and !dumpheap but it would be nice to know why the shortcut isn't there.Hewitt
Over time, some commands are changed with each .NET release. It's possible that -gen <num> has been removed unfortunately (for various, mysterious, reasons). Admittedly I tend to use the !EEHeap with !Dumpheap approach.Gaven
G
4

Another way to do this is with the finalizequeue command provided by SOS. This shows all objects registered for finalization, not just those that are ready for finalization:

0:010> !finalizequeue
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 33 finalizable objects (000000001b2b9710->000000001b2b9818)
generation 1 has 2 finalizable objects (000000001b2b9700->000000001b2b9710)
generation 2 has 580 finalizable objects (000000001b2b84e0->000000001b2b9700)
Ready for finalization 0 objects (000000001b2b9818->000000001b2b9818)
Statistics for all finalizable objects (including all objects ready for finalization):
              MT    Count    TotalSize Class Name
000007feebb95cb8        1           24 System.Threading.OverlappedDataCache
000007feebb81168        1           24 System.LocalDataStoreHolder
000007feebb14630        1           24 System.Threading.TimerHolder
000007feebb63a38        1           32 Microsoft.Win32.SafeHandles.SafePEFileHandle
000007feebb5ae38        1           32 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
000007feebb5ada8        1           32 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
...<snip>...
Total 615 objects

Then you can dump all objects in the generation 1 range of memory (clipping off the end since it won't be inclusive). I only have two in generation 1 here, fortunately:

0:010> dd 000000001b2b9700 000000001b2b9710-4
00000000`1b2b9700  02d51da0 00000000 02d51d50 00000000

Then dump those objects out (this is just the first one):

0:010> !do 02d51da0 
Name:        System.WeakReference
MethodTable: 000007feebb6cbb0
EEClass:     000007feeb53f1d8
Size:        24(0x18) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feebb6a338  4000688        8        System.IntPtr  1 instance           2128d8 m_handle
Gaslit answered 20/8, 2014 at 20:12 Comment(0)
C
2

You can use SOSEX's !finq command to list all the finalizable objects in each generation. See the SOSEX docs for usage.

Creeps answered 21/8, 2014 at 14:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.