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 be removed from this list. So 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 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: