ASP.NET Tips: Looking at the finalization queue
So in a previous post, we talked about Understanding when to use a Finalizer in your .NET class so now lets take a look at what the Finalize queue looks like and how to tell if things are bad.
The command we use is !finalizequeue in sos:
0:010> !finalizequeue
SyncBlock to be cleaned up: 86
----------------------------------
MTA interfaces to be released: 0
Total STA interfaces to be released: 0
----------------------------------
------------------------------
Heap 0
generation 0 has 6 finalizable objects (0x17a4e13c->0x17a4e154)
generation 1 has 0 finalizable objects (0x17a4e13c->0x17a4e13c)
generation 2 has 77 finalizable objects (0x17a4e008->0x17a4e13c)
Ready for finalization 0 objects (0x17a4e154->0x17a4e154) - Freachable queue
------------------------------
Heap 1
generation 0 has 0 finalizable objects (0x17ad591c->0x17ad591c)
generation 1 has 9 finalizable objects (0x17ad58f8->0x17ad591c)
generation 2 has 100 finalizable objects (0x17ad5768->0x17ad58f8)
Ready for finalization 2 objects (0x17ad591c->0x17ad5924) - Freachable queue
------------------------------
Heap 2
generation 0 has 2 finalizable objects (0x17a70920->0x17a70928)
generation 1 has 18 finalizable objects (0x17a708d8->0x17a70920)
generation 2 has 306 finalizable objects (0x17a70410->0x17a708d8)
Ready for finalization 11 objects (0x17a70928->0x17a70954) - Freachable queue
------------------------------
Heap 3
generation 0 has 0 finalizable objects (0x002295f4->0x002295f4)
generation 1 has 6 finalizable objects (0x002295dc->0x002295f4)
generation 2 has 155 finalizable objects (0x00229370->0x002295dc)
Ready for finalization 11 objects (0x002295f4->0x00229620) - Freachable queue
All Finalizable Objects Statistics:
MT Count TotalSize Class Name
0x166cea68 2 24 System.Data.OleDb.OleDbConnection/OleDbWrapper
0x79ba41f0 2 32 System.Threading.AutoResetEvent
0x79ba58b8 3 36 System.Security.Cryptography.RNGCryptoServiceProvider
0x160d40a8 3 48 System.Web.Security.FileSecurityDescriptorWrapper
0x19b3a7cc 1 56 System.Web.RegularExpressions.DataBindRegex
0x19b39434 1 56 System.Web.RegularExpressions.RunatServerRegex
0x19b393ac 1 56 System.Web.RegularExpressions.ServerTagsRegex
0x19b39324 1 56 System.Web.RegularExpressions.LTRegex
0x19b3929c 1 56 System.Web.RegularExpressions.GTRegex
0x19b39214 1 56 System.Web.RegularExpressions.TextRegex
0x19b3918c 1 56 System.Web.RegularExpressions.IncludeRegex
0x19b39104 1 56 System.Web.RegularExpressions.CommentRegex
0x19b3907c 1 56 System.Web.RegularExpressions.DatabindExprRegex
0x19b38ff4 1 56 System.Web.RegularExpressions.AspExprRegex
0x19b38f6c 1 56 System.Web.RegularExpressions.AspCodeRegex
0x19b38ee4 1 56 System.Web.RegularExpressions.EndTagRegex
0x19b38e5c 1 56 System.Web.RegularExpressions.DirectiveRegex
0x19b38dd4 1 56 System.Web.RegularExpressions.TagRegex
0x16c71ce8 1 56 System.Data.OleDb.DBPropSet
0x160da80c 1 56 System.Web.RegularExpressions.SimpleDirectiveRegex
0x79ba3e34 2 80 System.Runtime.Remoting.Lifetime.LeaseManager
0x16c72758 8 96 System.Data.OleDb.PropertyIDSetWrapper
0x160dad60 4 112 System.Web.Compilation.CompilationMutex
0x16c71434 2 128 System.Data.OleDb.DBBindings
0x79b97824 3 180 System.Runtime.Remoting.Contexts.Context
0x79b89c4c 4 208 System.IO.StreamWriter
0x15f490fc 11 220 System.Web.NativeDirMonCompletion
0x166cbe18 2 256 System.Data.OleDb.OleDbDataReader
0x16c75b74 5 280 System.Data.OleDb.OleDbDataAdapter
0x79b7ee18 5 320 System.IO.FileStream
0x79b7d004 20 320 System.Threading.ManualResetEvent
0x79ba438c 14 336 System.Threading.Timer
0x166cad9c 5 400 System.Data.OleDb.OleDbCommand
0x166c9d44 5 440 System.Data.OleDb.OleDbConnection
0x79b7df2c 17 476 Microsoft.Win32.RegistryKey
0x79ba8544 23 644 System.Security.Principal.WindowsIdentity
0x163f9734 25 700 Microsoft.VisualBasic.CompilerServices.ProjectData
0x163fa3e4 12 912 System.Data.DataSet
0x79b6e18c 28 1,792 System.Threading.Thread
0x163fbad0 13 2,912 System.Data.DataTable
0x79b7e8b0 216 3,456 System.WeakReference
0x16c73514 76 3,648 System.Data.OleDb.NativeDBType
0x160d6cd4 93 5,208 System.Text.RegularExpressions.Regex
0x163fcdd0 88 9,240 System.Data.DataColumn
Total 707 objects, Total size: 34,040
From this output we can see all of the objects that have been created that have a finalize method. If you call dispose on the object and it ends up calling GC.SuppressFinalize, then it will still be in this list, but will be able to be collected like an object that does not need to be finalized. So other then those objects, these are all of the objects that will need to be finalized. After each heap you will see a line about Ready for finalization… this show how many of the objects will need to run on the finalize thread currently. If you use the sos that comes with the debugger package (works only with 1.x version) you can add the -detail switch and see the Freachable Queue which is all of the objects that are ready to be finalized (GC.SuppressFinalize wasn't called but the object is ready to be cleaned up) as seen here:
Freachable Queue Statistics:
MT Count TotalSize Class Name
0x79b7d004 2 32 System.Threading.ManualResetEvent
0x16c72758 3 36 System.Data.OleDb.PropertyIDSetWrapper
0x79b89c4c 1 52 System.IO.StreamWriter
0x79ba8544 2 56 System.Security.Principal.WindowsIdentity
0x79b7df2c 2 56 Microsoft.Win32.RegistryKey
0x16c71ce8 1 56 System.Data.OleDb.DBPropSet
0x16c71434 2 128 System.Data.OleDb.DBBindings
0x79b7e8b0 10 160 System.WeakReference
0x166cbe18 2 256 System.Data.OleDb.OleDbDataReader
0x163fcdd0 3 396 System.Data.DataColumn
Total 28 objects, Total size: 1,228
When you see the !finalizequeue list showing thousands of objects, that is usually a sign that too many objects have a finalizer. The best way to troubleshoot this is to look for objects that are not part of the framework and then make sure that they follow the rules we discussed earlier.
There are other things that can go wrong with the finalizer but we will discuss them later. Some are already discussed on Tess’s blog.
A useful link about writing faster code is here. This also talks about calling GC.SuppressFinalize. There are also some very useful information in the following posts:
注释
-
DotNetKicks.com
2008年4月28日
You've been kicked (a good thing) - Trackback from DotNetKicks.com
-
Useful IIS/ASP.NET Information provided by Microsoft Support Teams
2008年4月28日
Want to see what objects you have added a finalizer too, follow the information here .
-
Nariman
2009年12月1日
Hi there; I think it's a mistake to suggest that GC.SuppressFinalize will 'remove' the object from the !finalizequeue in SOS - that you still see Systme.Data.DataTables (which call GC.SuppressFinalize) in their constructors is perfect evidence of this. Calling SuppressFinalize will prevent the promotion to FReachable and allow the object to be reclaimed on the first GC pass (just as non-finalizable objects would) but it will still list under this output. As such, this command in and of itself isn't very useful: a command in the *public* SOS that works for 2.x assemblies that shows FReachable or the Finalization Queue (where the bit in the header for finalization-requires is still set to ON) would help.
[1]-
http://www.devnewsgroups.net/dotnetframework/t19821-finalize-queue-windbg-sos.aspx
- ASP.NET Debugging2009年12月1日
Excellent point Nariman. I am updating the post to reflect that difference.