【问题标题】:Unregistering all events to release memory注销所有事件以释放内存
【发布时间】:2013-04-28 00:59:06
【问题描述】:

我有一个允许编辑产品信息的程序。我注意到关闭编辑表单后它没有释放内存。经过一些研究,我偶然发现了this 问题,其中提到问题可能在于它挂在事件订阅上。

这对我来说很有意义,因为此表单上有大约 100 多个控件,其中许多是自定义事件,这些事件由其父控件订阅。这会创建一个相当大的事件订阅层次结构。所以我寻找一种方法来发布这些,并找到了this,它允许你取消订阅该事件。

问题是,我有大量订阅。我真的必须在表单关闭时一个一个地手动取消订阅每个事件,还是至少有一种方法可以一口气释放它们,或者循环它们?

【问题讨论】:

标签: c# events


【解决方案1】:

记住这一点:+= 左侧的对象使包含+= 右侧方法的对象保持活动状态。也就是说,引发事件的对象使处理事件的对象保持活动状态,即使处理事件的对象(例如表单)已被释放。

所以你需要确保所有的事件引发者都已经离开了。

但是,如果所有事件引发器恰好是订阅这些事件的同一 Form 类中的控件,则您将不需要在表单被手动取消挂钩时关闭。

这是因为引发表单订阅的事件的控件与表单本身具有相同的生命周期。

您只需要担心如果您订阅的对象引发的事件的生命周期比订阅对象的生命周期长。 那么订阅对象(表单)需要在它(表单)被释放时取消订阅。

【讨论】:

  • 所以在这种情况下:Form => Control1 => Control2,每个都订阅正确的事件,只要 Control2 首先消失,级联应该没问题,并且所有事件都正确释放?
  • @Nick 是的,如果表单包含(直接或间接)这两个控件,应该没问题。一旦表单被释放,控件将无法从任何活动对象访问 - 但假设您在任何地方都没有对表单的任何引用!如果你这样做了,它是否被处理也没关系 - 它仍然可以访问,所以在这种情况下它仍然存在,以及它的所有控件。因此,在任何地方都没有对表单的任何非空引用非常重要!
  • 好的,所以在创建并显示在菜单项单击事件中的表单的情况下,没有其他对该表单的引用。当该窗体关闭时,理论上,它的所有子控件以及它们各自的事件都应该被释放?
  • @Nick:是的,它应该。但是表单可以在理论上获得一个外部事件并订阅它,或者它可以调用一个外部对象并传递“this”或对其字段之一的引用。有很多方法可以使一个对象以其他持有对它的引用的方式结束!您只能通过代码检查来检查 - 检查表单中的所有方法并确保它没有订阅外部对象或将“this”引用传递给可能挂在引用上的任何外部对象。 (希望你明白我的意思。)
  • @Nick:还有一件事:在工作中我们使用Redgate's ANTS Memory Profiler 有一个 14 天的免费试用期,所以你可以用它来检查一下。它非常适合发现这样的“漏洞”——但它确实有一点学习曲线。无论如何都要考虑一下。
【解决方案2】:

这取决于您的表单及其事件将存在多长时间。

但是,您可以循环访问表单中的控件,释放事件。 如果您意外删除了不存在的事件 - 不用担心,它不会引发异常。

例如,这是摆脱所有 TextBox.KeyDown-Events 的方法:

  private void frm_FormClosed(object sender, FormClosedEventArgs e)
    {
    foreach (Control tb in this.Controls)
    {
        if (tb is TextBox)
        {
            TextBox tb1 = (TextBox)tb;
            tb1.KeyDown -= TextBox_KeyDown;
        }
    }

【讨论】:

    猜你喜欢
    • 2014-05-29
    • 1970-01-01
    • 2013-07-06
    • 2017-12-30
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 2019-02-11
    • 1970-01-01
    相关资源
    最近更新 更多