代码之家  ›  专栏  ›  技术社区  ›  serhio

事件处理程序和内存泄漏

  •  5
  • serhio  · 技术社区  · 16 年前

    我分析了一个vb.net项目,有一些对象(子对象 MDI 形式)由 GC .

    MemoryProfiler分析发现,除其他外,以下内容:

    “此实例已释放,但仍然 由事件处理程序间接根。 这通常表明 事件处理程序未正确 是导致 内存泄漏。下面的实例是 由事件处理程序直接根。 调查他们以获得更多 有关此问题的信息…”

    现在,我试图弄清楚这意味着什么,以及如何修复它。

    我有MDI窗体和子窗体。打开/关闭后,GC不会收集子窗体,显然是因为它仍然(间接地?)由MDiform引用 EventHandlerList

    它可以是什么?如何修复它?

    我尝试了在 this thread ,因为中的MDI引用有问题 PropertyStore ,现在这已经消除了,但出现了MDI 事件处理程序列表 引用子窗体…

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

    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 回复  |  直到 12 年前
        1
  •  4
  •   Jeff Yates    16 年前

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

    我希望子窗体监视它的父窗体何时关闭(这是一个常见的用例),并且它没有取消订阅 FormClosing FormClosed 事件。不过,这只是一个猜测。若要确认,请查看子表单实现并查找它订阅父表单中事件的所有情况,然后确保这些事件中存在相应的取消订阅。

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

        2
  •  2
  •   Frederik Gheysels    16 年前

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

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

    推荐文章