Performance Issue Caused by Crashed Finalizer Thread
Customer had a newly developed .NET web application hosted in IIS 6. They recently experienced some performance issues inc. slow response, high memory consumption etc. We did a first tier analysis and decided to collect IIS crash dump. After a long monitoring, we got the 2nd chance process crash dump and there the story starts from.
First and foremost, I found the .NET exception generated when GC did object finalization:
# ChildEBP RetAddr
00 01e5f9d8 79f071ac kernel32!RaiseException+0x53
01 01e5fa38 7a10733d mscorwks!RaiseTheExceptionInternalOnly+0x2a8
…
0b 01e5fda8 79fb99d6 mscorwks!WKS::FinalizeAllObjects+0x56
0c 01e5fdc0 79ef3207 mscorwks!WKS::GCHeap::FinalizerThreadWorker+0xe7
0d 01e5fdd4 79ef31a3 mscorwks!ManagedThreadBase_DispatchInner+0x4f
0e 01e5fe68 79ef30c3 mscorwks!ManagedThreadBase_DispatchMiddle+0xb1
…
14 01e5ffec 00000000 kernel32!BaseThreadStart+0x34
Then dumped the object stack and there are several exception objects with the same exception type “NullReferenceException” and the same message “Object variable or With block variable not set”. Tried to print the exception out which could possibly show us the call stack. However, it doesn’t work
0:012> !PrintException 3c8e19f0
Exception object: 3c8e19f0
Exception type: System.NullReferenceException
Message: Object variable or With block variable not set.
InnerException: <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80004003
Then I suddenly recalled that customer specially complained that the memory consumption is quite huge while I also found the crash dump size is around 1G. Quite abnormal! Plus the NullReferenceException occurred in finalizing thread, I turned around to check the finalize/dispose source code.
It turned out that CU had managed and unmanaged objects/components called in his application and he realized his own Dispose() function but didn’t suppress finalization which would let the finalization code for the object to execute a second time. Thus, NullReferenceException might occur as the object had been disposed.
Solution:
========
Added “GC.SupressFinalize(this)”in Dispose().
Reference:
Implementing Finalize and Dispose to Clean Up Unmanaged Resources
https://msdn.microsoft.com/en-us/library/b1yfkh5e(vs.71).aspx
Clearing up some confusion over finalization and other areas in GC
https://blogs.msdn.com/maoni/archive/2004/11/04/252697.aspx
Regards,
Yawei Wang