【问题标题】:Event handler affects in garbage collection in CLR事件处理程序影响 CLR 中的垃圾收集
【发布时间】:2017-12-09 14:30:59
【问题描述】:

我对事件处理程序如何影响垃圾回收操作感到完全困惑。

比如为什么对象a1没有被垃圾回收(a1的析构函数没有调用):

即使在取消订阅 timeChange eventHandler 之后,垃圾收集器也不会调用析构函数。

最好的问候。

public class B
{
    private void button1_Click(object sender, EventArgs e)
    {    
        A a1 = new A();
        a1.timeChange += A1_timeChange;

        a1.Start();

        a1 = null;

        GC.Collect();
    }

    private void A1_timeChange(object sender, EventArgs e)
    {
        MessageBox.Show(((DateTime)sender).ToString() );
    }
}

public class A
{
    ~A()
    {
        MessageBox.Show("A Collected");
    }

    public void Start()
    {
        if (timeChange != null)
        {
            Task.Factory.StartNew(() => {
                while (true)
                {
                    timeChange(DateTime.Now, null);
                    System.Threading.Thread.Sleep(3000);
                }
            });
        }
    }
    public event EventHandler timeChange;
}

【问题讨论】:

  • 任务通过this.timeChange 成员保持引用,this 变为未定义将是灾难性的。 while (true) 循环确保它永远被引用。任意将事件设为静态,您现在会看到它被收集起来。

标签: c# .net winforms garbage-collection eventhandler


【解决方案1】:

总结
造成这种情况的不是事件本身,而是使用闭包从长时间运行的线程中引用 A 类的实例成员。

事件本身不是问题,不是吗?
此代码 a1.timeChange += A1_timeChange; 导致类 A 内的委托实现事件 public event EventHandler timeChange 引用类 B 内的 A1_timeChange
所以,参考是其他方式
在您的场景中,如果您删除了对 B 类的所有引用,但没有取消订阅该事件,则 A 中指向 B 中的处理程序方法的事件处理程序可以保持 B 类可访问,因此不会被 GC'ed

真正发生的事情
您的 A 类可以从 GC 根之一(特别是主动运行的线程)访问,它仍然可以访问,因此不会被收集 - read more

您已经使用此代码生成了一个永久运行的任务(它会在应用关闭/前台线程终止时停止)

Task.Factory.StartNew(() => {
                while (true)
                {
                    timeChange(DateTime.Now, null);
                    System.Threading.Thread.Sleep(3000);
                }

问题是,您正在使用关闭 timeChange 事件的 lambda,这使得编译器生成一个仅引用类 A 的类

还有一件事,只需使用析构函数(编译为终结器),您就可以通过一次 GC 集合延长对象的生命周期 - 在第一次 GC 时,您的对象将被标记为不可访问,并将被放入终结队列。而在 next GC 上,终结器将实际运行 - read more

【讨论】:

    猜你喜欢
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2011-07-03
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    相关资源
    最近更新 更多