.NET无法诊断USER对象泄漏

时间:2016-03-10 12:58:07

标签: .net memory-leaks

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

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

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

在此过程中,我看到以下内容: USER / 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使用快照,例如我发现在两个快照之间可能只有4个对象在迭代开始时不存在 - 所有四个都是未记录的实例System.Windows.Forms.Command。然而,USER对象数量已经增加了!

这告诉我,代码中的某些内容未正确处理/释放其中一些非托管USER对象。它显然不是管理对象的问题(除了4个虚假的Command对象,我不知道他们做了什么)。

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

所以我的问题是:如何找出正在使用的USER和GDI对象?内存分析器似乎无法涵盖这一点。我已经为USER对象尝试过UISpy,但在这个例子中似乎没用。它显示了我期望使用的所有内容,但没有显示其他内容。

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

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

1 个答案:

答案 0 :(得分:0)

需要一段时间来识别,但在经过大量调试和评论代码后,我将其缩小为Infragistics UltraTextEditor。如果我设置AlwaysInEditMode = True然后我得到这个泄漏。如果我将其设置为False,那么我不会。同样,如果我只是将另一个UltraTextEditor添加到用户控件(并且不对它执行任何操作)并设置AlwaysInEditMode = True,那么我也会得到泄漏。

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

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

所以,开发人员错误。但这是一个真正的困难。内存分析没有显示问题。没有任何东西可以让你追踪野生的USER对象。如果我能够看到它们代表什么,那么识别模式和整个问题就会容易得多。另外使用Infragistics有点模糊不清的东西,因为作为一个黑盒子,你真的不知道,或者不需要知道封底下发生的事情。哪个没用,直到它不起作用!

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