Остановили ли обработчики событий сбор мусора?

183

Если у меня есть следующий код:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;

Будет ли pClass собирать мусор? Или он будет зависать, продолжая стрелять в события, когда они происходят? Нужно ли делать следующее, чтобы разрешить сборку мусора?

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;
Марк Инграм
источник
11
Я собираюсь предварительно предложить читателям, заинтересованным в этом вопросе, что, возможно, стоит ознакомиться с облегченными событиями / шаблонами слабых событий, которые НЕ предотвращают сбор мусора. Хороший SO самозагрузка в эту тему stackoverflow.com/questions/185931/...
fostandy
20
Примечание для потомков: установка ссылки на null просто задерживает сборщик мусора, расширяя на одну строку область действия ссылки. .NET не VB6.
Джон Сондерс

Ответы:

207

Для конкретного вопроса «Будет ли pClass собирать мусор»: подписка на событие не влияет на сборку pClass (как издателя).

Для GC в целом (в частности, для цели): это зависит от того, является ли MyFunction статической или основанной на экземплярах.

Делегат (такой как подписка на событие) для метода экземпляра включает в себя ссылку на экземпляр. Так что да, подписка на событие помешает GC. Однако, как только объект, публикующий событие (pClass выше), подходит для сбора, это перестает быть проблемой.

Обратите внимание, что это односторонний; т.е. если у нас есть:

publisher.SomeEvent += target.SomeHandler;

тогда «издатель» будет поддерживать «цель» живым, но «цель» не будет поддерживать «издателя» живым.

Так что нет: если pClass будет собираться в любом случае, нет необходимости отписываться от слушателей. Однако, если Pclass был долгожителем (больше , чем например , с MyFunction), то Pclass может сохранить этот экземпляр живым, так что это было бы необходимо отказаться , если вы хотите, чтобы цель , чтобы быть собраны.

Однако по этой причине статические события очень опасны при использовании с обработчиками на основе экземпляров.

Марк Гравелл
источник
6
Что ж, если вопрос «будет ли pClass собирать мусор», то ответ «это зависит от того, будет ли ...» на самом деле не верен. Это не зависит ни от чего, как отмечает сам Марк ниже.
Тор Хауген
@Tor - достаточно справедливо - я поясню
Марк Gravell
Хотя делегат подписки на событие указывает только в одну сторону, подписчику, который намерен отказаться от подписки на событие, когда оно завершено, потребуется некоторая форма ссылки на издателя. Это может быть WeakReference, а в некоторых случаях это может быть хорошей идеей, но часто это будет сильной идеей.
суперкат
Отличный ответ, потому что он также затрагивает другую половину вопроса (который не задавался): издатель остановит подписчика от GC'd.
Боб
Да, и, как сказал @BobSammers, действительно может возникнуть проблема, если экземпляр с коротким сроком действия, такой как Форма / Окно, подписывается на службу с длительным сроком службы, например Singleton, которая предоставляет данные, например: Singleton сохраняет ссылку и объекты сохраняются в памяти, даже когда мы думаем, что они выгружены! Так что будьте очень осторожны при использовании событий. Мы злоупотребляли событиями для нашего большого программного обеспечения, и потом это очень трудно решить.
Elo
9

Да, pClass будет собирать мусор. Подписка на событие не означает, что существует какая-либо ссылка на pClass.

Так что нет, вам не придется отсоединять обработчик, чтобы pClass собирал мусор.

Тор Хауген
источник
8

В тот момент, когда на часть памяти больше не ссылаются, она становится кандидатом на сборку мусора. Когда экземпляр вашего класса выходит из области видимости, ваша программа больше не ссылается на него. Он больше не используется и поэтому может быть безопасно собран.

Если вы не уверены, что что-то будет собрано, задайте себе следующий вопрос: существует ли еще ссылка на это? На обработчики событий ссылается экземпляр объекта, а не наоборот.

lvaneenoo
источник
0

pClassбудет мусор. Однако, если приведенный выше фрагмент кода находится внутри другого класса, экземпляр этого класса может быть не очищен, если вы не установите pClassего null.

Арав
источник