We have a WinForms application installed in hundreds of clients. In some of them, memory usage starts going up over time with apparent no reason, until an OutOfMemoryException is eventually thrown.
We used DebugDiag Collection and Analysis to try to understand the problem. We got these warnings.
So, first thing to look at was the Finalizer thread, as there was a huge queue of objects (42K) ready for finalization. This is how its call stack looked like at the time of the dump:
ntdll!KiFastSystemCallRet
ntdll!NtWaitForSingleObject+c
KERNELBASE!WaitForSingleObjectEx+98
kernel32!WaitForSingleObjectExImplementation+75
clr!CLREventBase::Reset+17e
clr!CLREventBase::Reset+1c6
clr!CLREventBase::WaitEx+152
clr!FinalizerThread::WaitForFinalizerEvent+38
clr!FinalizerThread::FinalizerThreadWorker+5f
clr!Thread::DoExtraWorkForFinalizer+1b1
clr!Thread::DoExtraWorkForFinalizer+234
clr!Thread::DoExtraWorkForFinalizer+5f8
[[DebuggerU2MCatchHandlerFrame]]
clr!ManagedThreadBase::FinalizerBase+33
clr!FinalizerThread::FinalizerThreadStart+d4
clr!Thread::intermediateThreadProc+55
kernel32!BaseThreadInitThunk+e
ntdll!__RtlUserThreadStart+70
ntdll!_RtlUserThreadStart+1b
Same process, five hours later, and the warnings shown by DebugDiag are these.
So, alledgedly leaked memory almost doubled as number of objects ready for finalization went significantly up. The Finalizer thread call stack was identical to the previous one. Indeed, the problem seems to reside in a blocked finalized thread, making it impossible for the GC to get rid of unused objects.
Thing is, we don't use finalizers in our code. What blocking operation might the finalizer thread be doing? How could we find out if there is an external module responsible for this, and which one it is?
Some extra info: We are using .NET Framework 4.0, and our application is compiled for x86. The problem is more likely to reproduce in Windows 7+ SOs, while XP ones seem to behave better.
Any help or hint about where to look will be much appreciated.
for what it's worth: I had a comparable situation, some years ago. gdi errors are typical when your program runs out of resources. Finally I used redgate's Ants (free trial period) to find out that a lot of objects were kept in memory. I used VB.NET, and it is a little known fact that variables declared with 'withevents' need to be explicitly set to nothing in the finalizer. Also passing and keeping references to other objects is a potential reason why the garbage man doesn't come along. Setting those references to nothing (null) in the finalizer helps. In VB, the finalizer code for the form is in the designer file:
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
If Me.DesignMode Then Exit Sub
If disposing Then
JCboKind.DataSource = Nothing
JCBOCondition.DataSource = Nothing
JCboQuality.DataSource = Nothing
JCboSafetyCategory.DataSource = Nothing
JcboSurfTreatment.DataSource = Nothing
JCboUnit.DataSource = Nothing
End If
...