.NET 无法诊断用户对象泄漏



我有一个WinForms应用程序,它非常大,但我使用任务管理器检测到用户对象泄漏(和较小的GDI泄漏)。

应用程序运行后,我将打开一个窗体,其中显示从服务器组件(使用 WCF)检索的一些数据。然后我关闭表单。为了测试,我正在运行垃圾收集。

然后,我通过用户和GDI计数的任务管理器进行基本注释,并重复打开/关闭/收集多次。

在此过程中,我看到以下内容:用户/GDI 计数

824/347

830/349

835/349

867/361

872/361

876/361

908/371

940/381

945/381

977/391

现在考虑到我一直在执行相同的操作,我不明白为什么 USER/GDI 增加是非线性的。如果一切都被正确处理,它实际上应该是零,或者大部分为零。

我尝试在操作前后使用快照使用 JetBrains DotMemory,例如,我发现在 2 个快照之间可能只有 4 个对象在迭代开始时不存在 - 所有四个都是未记录的 System.Windows.Forms.Command 的实例。然而,用户对象计数增加了!

这向我表明代码中的某些内容没有正确处理/释放其中一些非托管 USER 对象。问题显然不是托管对象(除了 4 个虚假的 Command 对象,我不知道它们的作用)。

我的代码不使用任何非托管资源 - 它调用Microsoft类和Infragistics类。现在我知道Infragistics以泄漏而闻名,但通常这与静态绑定对象有关,并且根据DotMemory的说法,这里没有发生(已经处理了删除这些对象的使用)。我还希望重复操作显示线性泄漏。

所以我的问题实际上是:如何找出正在使用哪些 USER 和 GDI 对象?内存分析器似乎没有涵盖这一点。我已经为用户对象尝试了UISpy,但在这种情况下似乎毫无用处。它显示了我希望使用的所有内容,但没有显示其他内容。

我更关心 USER 对象,因为它们增长得更快,并且更有可能在应用程序重启之间突破 10,000 个限制,但虚假的 GDI 增加当然也让我感兴趣。

我不反对这里和那里的一点泄漏,因为它可能不会造成影响,我宁愿开发时间花在富有成效上,而不是诊断可能存在于第三方组件中的小泄漏无论如何都很难修复。

识别需要

一段时间,但经过大量的调试和注释代码,我将其缩小到Infragistics UltraTextEditor。如果我设置了 AlwaysInEditMode=True,那么我就会得到这个泄漏。如果我将其设置为 False,那么我不会。同样,如果我只将另一个UltraTextEditor添加到用户控件(并且不对它执行任何操作)并设置AlwaysInEditMode=True,那么我也会出现泄漏。

我厌倦了在一个小型测试项目中重现它,但无法继续调查。

我最终发现的是一个面板,该面板在用户控件的深处被删除(当显示部分有效折叠时),其中包含Infragistics UltraTextEditor的三个实例以及其他一些Windows控件。现在看来,面板和控件正在被垃圾回收(没有引用),但它们没有被处理。对于非基础设施控件来说,这似乎无关紧要(我猜他们不使用非托管资源?),但Infragistics控件有一个未被清理的USER对象。Infragistics UltraTextEditor的工作方式有点奇怪。它由两个文本框组成,一个我认为是标准的MS文本框,另一个是Infragistics开发的文本框。在正常操作中,当控件具有焦点时,它显示一个,当失去焦点时显示另一个。通过设置 AlwaysInEditMode=True,我认为它必须在此时处理其中一个(具有非托管资源的那个)。因此,当尚未设置此选项时,当控件最终被垃圾回收而未被释放时,它必须使未托管的资源保持未释放状态。

所以,开发人员错误。但这是一个真正的艰难。内存分析未显示问题。而且没有什么可以让你追踪野生用户对象。如果我能够看到它们代表什么,那么识别模式和整个问题就会容易得多。此外,使用Infragistics有些模糊了事情,因为作为一个黑匣子,你并不真正知道或需要知道幕后发生了什么。这很好,直到它不起作用!

我仍然没有非线性性质的答案,但当然框架在后台做各种各样的事情,响应鼠标移动和进入/离开事件。需要一个像样的用户对象分析器!

最新更新