排除内存泄漏可能是由于终结器线程故障

时间:2017-09-29 08:20:40

标签: .net winforms memory-leaks finalizer

我们在数百个客户端安装了WinForms应用程序。在其中一些中,内存使用率随着时间的推移开始上升,显然没有理由,直到最终抛出OutOfMemoryException。

我们使用DebugDiag Collection and Analysis来尝试理解这个问题。我们得到these warnings

所以,首先要看的是Finalizer线程,因为有一个庞大的对象队列(42K)可以完成。这就是转储时其调用堆栈的样子:

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

相同的过程,五个小时后,DebugDiag显示的警告为these

因此,由于准备好最终确定的对象的数量大幅增加,因此泄密内存几乎翻了一番。 Finalizer线程调用堆栈与前一个相同。实际上,问题似乎存在于一个被阻止的最终线程中,使GC无法摆脱未使用的对象。

事实是,我们的代码中没有使用终结器。终结器线程可以执行哪些阻塞操作?我们怎么能知道是否有一个外部模块对此负责,以及它是哪一个?

一些额外信息:我们使用的是.NET Framework 4.0,我们的应用程序是针对x86编译的。这个问题更有可能在Windows 7+ SO中重现,而XP似乎表现得更好。

非常感谢任何关于在哪里观看的帮助或暗示。

1 个答案:

答案 0 :(得分:1)

它的价值: 几年前,我有类似的情况。当您的程序资源耗尽时,gdi错误是典型的。最后,我使用了redgate的蚂蚁(免费试用期)来发现很多物体被保存在记忆中。我使用VB.NET,一个鲜为人知的事实是,使用'withevents'声明的变量需要在终结器中显式设置为空。传递和保持对其他物体的引用也是垃圾人没有出现的潜在原因。在终结器中将这些引用设置为空(null)会有所帮助。在VB中,表单的终结器代码位于设计器文件中:

 '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
        ...