【问题标题】:Can Delegates cause memory leaks?委托会导致内存泄漏吗?
【发布时间】:2010-02-09 08:46:43
【问题描述】:

委托会导致内存泄漏吗?

我的意思是,例如如果一个类A 包含一个ADelegate 并且后者指向BMethod(属于B 类)这是否可以防止GC 收集A 类或B 类?

如果是这样,我们如何“释放”代表(设置 ADeletate = Nothing / null?)

你怎么评价这个:

//Class A Finalize, containing ADelegateInstance as ADelegate'
protected override void Finalize()
{
    ADelegateInstance = 
        (ADelegate)System.Delegate.RemoveAll(
            ADelegateInstance, ADelegateInstance);
    ADelegateInstance = null;
    base.Finalize();
}

'Class A Finalize, containing ADelegateInstance as ADelegate'
Protected Overrides Sub Finalize()
    ADelegateInstance = _ 
        CType(System.Delegate.RemoveAll(ADelegateInstance, ADelegateInstance), _ 
            ADelegate)
    ADelegateInstance = Nothing
    MyBase.Finalize()
End Sub

【问题讨论】:

    标签: .net memory-leaks delegates


    【解决方案1】:

    是的,除非您取消订阅该事件,否则该引用将保持有效:

    someObject.SomeEvent -= SomeDelegate;
    

    【讨论】:

    • 如果我有一个具有多个委托订阅/取消订阅的大型复杂对象,最后在 Dispose 这个对象中我想“让死”这个委托的所有链接。
    • 然后就可以实现IDisposable了。
    • 是的,我应该在该委托的 Dispose 方法中写什么。 ,也许System.Delegate.RemoveAll(myDelegate, myDelegate) 会有所帮助?
    • 你会像我在我的例子中播种的那样做。
    • @serhio:语法几乎不是问题的重点。概念是一样的。
    【解决方案2】:

    仅仅有一个引用并不足以导致内存泄漏。请考虑以下内容。

    如果一个线程产生 3 个对象(其中 -> 表示引用),A -> B -> C -> A

    如果线程没有引用A,则全部收集。循环引用由 GC 处理。

    不过,这也显然意味着,如果一个委托包含对一个对象的引用,并且该委托的对象仍然被引用,那么委托函数将不会被清理。

    这将为您提供以下内容。

    A - (带有委托的对象) B - 包含函数引用的对象。

    当 A 超出范围时,B 也会这样做。

    【讨论】:

      【解决方案3】:

      AFAIK,闭包/委托所指的上下文确实不能被垃圾收集,只要闭包/委托仍然被引用——否则它会丢失它的上下文。

      answer 为例,我们看到委托可以在对象的上下文中引用变量inneri。所以实际持有inneri的对象不能被垃圾回收,直到不再引用委托,在这种情况下,直到Button被垃圾回收。

      for (int i = 0; i < 7; i++)
      {
          var inneri = i;
          Button newButton = new Button();
          newButton.Text = "Click me!";
          newButton.Click += delegate(Object sender, EventArgs e)
          {
              MessageBox.Show("I am button number " + inneri);
          };
          this.Controls.Add(newButton);
      }
      

      相关帖子:

      【讨论】:

      • 也就是说,你的意思是只要ADelegate指向B就不会被收集?..
      【解决方案4】:

      如果 A 包含 B 中函数的委托,则 A 不会被 GC 销毁。

      每次编写“mydelegate += B.method”时始终输入“mydelegate -= B.method”是个好主意。

      虽然这不是真正的内存泄漏,因为仍然可以访问对象。

      【讨论】:

        【解决方案5】:

        有一种情况是在 ASP.NET 应用程序中使用了单例。由于某种原因,它曾经订阅控件事件。它是一个单例(包含对自身的引用)这一事实不允许 GC 收集它,另一方面,单例从未删除对控制事件的订阅。这导致了内存消耗的永久增长:用于服务单个请求的控件由于来自单例的现有引用而未被 GC 清理,为每个新请求创建新控件。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-01-02
          • 2021-03-23
          • 2021-09-25
          • 2014-12-08
          • 1970-01-01
          • 1970-01-01
          • 2010-09-09
          相关资源
          最近更新 更多