垃圾收集器清除对象是否订阅了事件?

时间:2009-05-29 21:44:34

标签: c# memory-leaks garbage-collection

如果我执行以下操作:

public class Test
{
    public static void Main()
    {
        List<Person> persons = new List<Person> { new Person() };

        persons[0].Sneezing += new EventHandler(Person_Sneezing);

        persons = null;
    }

    public static void Person_Sneezing(object sender, EventArgs e)
    {
        (sender as Person).CoverFace();
    }
}

亲自[0]的人是否仍然存在于内存中,因为它的打喷嚏代表有对Person_Sneezing方法的引用或是否由GC收集?

3 个答案:

答案 0 :(得分:8)

这将由GC收集。要保留在内存中,对象必须由...直接或间接引用。

  1. 堆栈上的值
  2. 以强GC句柄为根的值
  3. 目前我还没想到的一两个角落
  4. 对于人物[0]的物体不是这样。所以它将被收集。

    当然,假设Person()的构造函数没有做任何有趣的事情,比如将自己添加到ThreadLocalStorage。

答案 1 :(得分:6)

你已经到了一半;如果它是其他方式,这将是一个内存泄漏。也就是说,如果它看起来像这样:

public class Test
{
    public void HookupStuff()
    {
        List<Person> persons = new List<Person> { new Person() };

        this.EventHappened += new EventHandler(persons[0].SomeMethod);
        // persons[0].Sneezing += new EventHandler(Person_Sneezing);

        persons = null;
    }
}

现在persons[0]会坚持下去,即使你排除了persons,因为父类有一个方法可以引用它。

答案 2 :(得分:1)

除了你已经得到的答案之外,你需要在更现实的例子中小心。

如果您的应用程序有一个主窗口,只要程序运行就会存活,并且您经常创建“短期”对象,将其方法登记到主窗口上的事件,那么您必须从这些事件中删除对象。你不再需要它们,因为否则这些对象根本就不会“短暂” - 它们只要在主窗口中存活,即直到用户关闭应用程序。有效的结果将等同于内存泄漏。

如果您创建短期对象的类实现IDisposable,它可以帮助您,因此您可以从Dispose中的事件中退出,然后确保在要放弃对象时调用dispose