我需要他们成为孤儿前,从对象中删除事件订阅?(Do I need to remove event s

2019-06-24 19:42发布

如果我的软件有两个对象实例,其中一个订阅到其他的事件。 我需要从一个退订他们,他们是孤立的另一个之前,他们被垃圾收集器进行清理? 或者有没有其他的原因,我应该清除事件的关系? 如果什么对象的订阅是孤立的,但用户不是,反之亦然?

Answer 1:

是的你是。 该事件发布者都是抱着引用的对象,并会防止它们被垃圾收集。

让我们看一个例子,看看会发生什么。 我们有两类: 一个公开的事件,其他消耗它:

class ClassA
{
    public event EventHandler Test;
    ~ClassA()
    {
        Console.WriteLine("A being collected");
    }
}
class ClassB
{
    public ClassB(ClassA instance)
    {
        instance.Test += new EventHandler(instance_Test);
    }

    ~ClassB()
    {
        Console.WriteLine("B being collected");
    }

    void instance_Test(object sender, EventArgs e)
    {
        // this space is intentionally left blank
    }
}

注意ClassB的怎么不存储在ClassA的实例的引用; 它只是挂接事件处理程序。

现在,让我们来看看对象是如何收集的。 方案1:

ClassB temp = new ClassB(new ClassA());
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();

我们创建了一个ClassB的实例,并通过持有临时变量的引用它。 它被传递ClassA的,在这里我们不参照存储在任何地方的新实例,如此这般的ClassB的构造完成后超出范围立即。 我们有垃圾收集器的ClassA时已超出范围运行一次,而且一旦当为超出范围ClassB的。 输出:

Collect 1
A being collected
Collect 2
B being collected

方案2:

ClassA temp = new ClassA();
ClassB temp2 = new ClassB(temp);
temp2 = null;
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();

创建ClassA的的一个新实例和对它的引用存储在临时变量。 然后ClassB的新实例被创建,获得在温度传递给它的ClassA的实例,我们存储在TEMP2对它的引用。 然后我们设置TEMP2为null,使ClassB的实例走出去的范围。 和以前一样,我们有垃圾收集器运行的每个实例已超出范围后。 输出:

Collect 1
Collect 2
B being collected
A being collected

因此,得出结论; 如果暴露事件实例超出范围,就成了可进行垃圾回收,而不管是否有事件处理程序挂钩与否。 如果有一个事件处理程序实例在另一个实例迷上了一个事件,也不会进行垃圾回收,直到事件处理程序被分离,或事件处理程序连接到该实例变为可进行垃圾回收。



Answer 2:

你只需要解开事件的暴露 ,如果这些事件的对象是长寿命的,但挂钩的事件的对象,否则将是短暂的(并获得快速的垃圾收集相当)。

在这种情况下,未能解开会造成相当于一个内存泄漏,因为你短暂的对象将不能被GCed - 因为在长期目标的情况下持有到一个代表,它拥有一个参考短命的对象。 由于短暂的对象仍是由委托引用,它不能让垃圾收集。

静态事件,长寿命的定义 - 他们生活,直到程序退出。 如果你勾静态事件,你一定要解开它时,你就大功告成了。

如果两个对象是即将被孤立,脱钩是没有必要的。



Answer 3:

订阅一个强有力的参考订户的事件的结果。 这是因为,在幕后,事件是代表,并委托给实例方法是对象参考和实际方法的组合。 如果不取消,出版商将继续保持引用和订阅对象永远不会得到真正的孤儿(和GC'ed),只要出版商还活着。

即,订阅对象不具有给发布商的任何参考反向是不正确的。



文章来源: Do I need to remove event subscriptions from objects before they are orphaned?