Удаляет ли сборщик мусора объекты, подписанные на события? - PullRequest
5 голосов
/ 30 мая 2009

Если я сделаю следующее:

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], все еще существует в памяти, поскольку его делегат Sneezing имеет ссылку на метод Person_Sneezing, или он собирается GC?

Ответы [ 3 ]

8 голосов
/ 30 мая 2009

Это будет собрано GC. Чтобы быть сохраненным в памяти, объект должен ссылаться прямо или косвенно ...

  1. значение в стеке
  2. Значение, коренящееся в сильной ручке GC
  3. Уголок или два, о которых я сейчас не думаю

Это не относится к объекту у лиц [0]. Так и будет собрано.

Это, конечно, при условии, что конструктор для Person () не делает ничего смешного, например, добавляет себя в ThreadLocalStorage.

6 голосов
/ 30 мая 2009

Ты на полпути; это было бы утечкой памяти, если бы было наоборот. То есть, если бы это выглядело так:

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, так как родительский класс имеет ссылку на метод.

1 голос
/ 30 мая 2009

В дополнение к ответам, которые вы уже получили, вы должны быть осторожны в более реалистичных примерах.

Если в вашем приложении есть главное окно, которое сохраняется до тех пор, пока выполняется программа, и вы часто создаете «недолговечные» объекты, которые привязывают их методы к событиям в главном окне, тогда вы должны исключить объекты из этих событий, когда они вам больше не нужны, потому что иначе эти объекты вообще не будут «недолговечными» - они будут существовать до тех пор, пока основное окно не будет закрыто, то есть до тех пор, пока пользователь не закроет приложение. Эффективный результат будет эквивалентен утечке памяти.

Может помочь, если вы реализуете класс недолговечного объекта, реализующий IDisposable, так что вы можете исключить события из Dispose, а затем убедиться, что вы вызываете dispose, когда хотите сбросить объект.

...