事件处理程序和内存泄漏

时间:2010-02-05 13:40:34

标签: .net .net-2.0 memory-leaks event-handling

我分析了一个VB.NET项目,并且有一些对象(子MDI形式)被处置,但GC没有删除。

MemoryProfiler分析发现以下内容:

  

“这个实例已经处理好了   间接由EventHandler根源。   这通常表明了   EventHandler没有正确使用   删除,是一个常见的原因   内存泄漏。以下实例是   直接由EventHandler生成。   调查他们以获得更多   有关此问题的信息......“

现在,我试着弄清楚这应该是什么意思以及如何解决它。

我有一个MDI表格和一个子表格。 GC打开/关闭后不会收集子表单,显然是因为MDIForm EventHandlerList引用了仍然(间接?)...

它可以是什么,我该如何解决它?

我尝试了this thread中建议的修复,因为PropertyStore中的MDI引用存在问题,现在已经消除了,但出现了对子窗体的MDI EventHandlerList引用。 ..

经过一些代码分析后,我观察了一些

AddHandler newMenu.Click, AddressOf ClickMenu

不在RemoveHandler newMenu.Click, AddressOf ClickMenu之前。这可能是主要原因吗?

而且,一个提议,是Handles

Private Sub ClickMenu(sender as Object, e as EventArgs) Handles newMenu.Click

更好的

RemoveHandler newMenu.Click, AddressOf ClickMenu
AddHandler newMenu.Click, AddressOf ClickMenu

从内存分配的角度来看?

2 个答案:

答案 0 :(得分:4)

EventHandlerList由提供大量事件的类使用,通过仅在需要时为事件支持字段分配空间而不是在声明事件时为其更有效地处理内存。因此,主表单的所有事件都存储在那里。

我希望子窗体在其父窗口关闭时进行监控(这是一个常见的用例),并且在收到该事件时它没有取消订阅FormClosingFormClosed事件。但是,这只是猜测。要确认,请查看您的子表单实现,并查找从父表单订阅事件的所有情况,然后确保这些事件中有相应的取消订阅。

<强>更新
您找到的未删除的菜单处理程序很可能是您看到的问题的根源。尝试添加删除调用,看看是否解决了泄漏问题。

答案 1 :(得分:2)

还有另一个对象引用了GC应该通过事件处理程序删除的对象。含义:还有另一个对象仍然订阅了被处置对象的事件。

如果要处置该对象,可以通过取消订阅事件(从事件中删除事件处理程序)来解决此问题。