【问题标题】:Memory leak - probably 'cause of to many eventhandlers内存泄漏 - 可能是许多事件处理程序的原因
【发布时间】:2015-08-10 08:29:57
【问题描述】:

我想我在我的桌面应用程序(.NET 4.0、WinForms、VB.NET)中发现了内存泄漏。不幸的是,我无法解释为什么会发生。

我有一个 Form 和一个自定义-TabControl(继承自 XtraTabControl - DevExpress)。这个TabControl 在每个TabPage 中显示一组不同的客户。如果您双击一行(客户),我会打开一个新的Form,其中包含客户的所有详细信息。在这个新的Form 中有一些DataGrids(同样是使用来自DevExpress 的GridControlGridView 的自定义控件)和许多其他控件(LabelsTextBoxes 等)。如果 detail-Form 已打开,则会使用新的客户数据进行更新。

以下是内存泄漏的一些事实:

  • 启动应用程序后:已使用 77 Mb RAM; 2.640 EventHandlers 持有 90 Kb RAM
  • 打开 25 个客户后:已使用 190 Mb; 75.016 EventHandlers 持有 127 Mb RAM
  • 关闭两个表单后:仍然使用 190 Mb,66.216 EventHandlers 持有 132 Mb RAM

我尝试System.GC.Collect(2, GCCollectionMode.Forced) 只是为了好玩(我知道我不应该这样做),但它根本没有改变任何东西。

我知道事件的发布者持有对订阅者的引用,因此如果发布者的寿命比订阅者的寿命长,那么它将使订阅者保持活动状态。但是如果我关闭所有两个Forms,不应该都很好吗?

编辑:这是打开 25 个客户并关闭 2 个表单后的内存屏幕截图。看起来,内存中还有很多控件:( (列翻译:对象类型 | 计数 | 大小 | 持有内存大小)

编辑 2:这是 ANTS Memory Profiler 的另一个屏幕截图。不幸的是,我无法从中得到线索:

希望大家能帮帮我,先谢谢了!

【问题讨论】:

  • 这可能不是“内存泄漏”。让您的应用程序打开 10 分钟以查看 RAM 是否减少。想看看的想法 - 关闭后尝试Disposing 表单。此外,如果您调用AddHandler 以编程方式添加事件处理程序,您应该在某处调用RemoveHandler
  • 我试试。以为我可以用System.GC.Collect() 模拟它,所以我不必等待。这两种形式得到处理。我还检查了是否所有子控件也都被释放了 - 效果很好(来自设计器的 Dispose-Code)。
  • 获取 JetBrains dotMemory 等内存分析器,并在关闭表单后检查您的对象是否仍在内存中
  • 我在打开 25 个客户并关闭 2 个表单后添加了一个屏幕截图。内存中还有很多控件。但为什么?关闭 2 个表单后,任何控件都不应有任何引用(或者我误解了什么)?
  • @roli09 我不熟悉这个分析器,它可以显示从根到泄漏对象的路径吗?看看它,你很可能会明白为什么它还在记忆中。

标签: .net vb.net winforms memory-leaks


【解决方案1】:

感谢您的帮助。我想我明白了!

我安装了 .NET Memory Profiler 5.0,这个应用程序向我展示了持有 GridViewsevent 的调用堆栈。然后我在我的自定义控件中实现了一些Dispose-methods,目前我正在恢复几乎所有的记忆。

顺便说一句:在Dispose-Method 中删除EventHandlers 是不是一个糟糕的设计?

【讨论】:

  • Dispose 中删除EventHandlers 是什么意思?退订?
  • 是的,我的意思是退订。
  • Dispose 是退订任何活动的绝对正确位置。 Disposing 意味着对象的逻辑生命周期结束,GC 稍后会收集它,但从应用程序的角度来看,disposing 的对象是死对象。
猜你喜欢
  • 2011-01-13
  • 2023-03-08
  • 2012-10-29
  • 2012-05-31
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多