Объект Timer получает GC-ed, когда на него не ссылается другой объект?

Может ли объект, содержащий активный таймер (System.Timers.Timer), быть сборщиком мусора, если на него не ссылается никакой другой объект?


person froeschli    schedule 10.02.2011    source источник


Ответы (2)


Есть два основных способа, которыми Timer остается ссылкой, даже если вы где-то не храните ссылку:

  • Пока таймер включен. Существует базовый System.Threading.Timer, который фактически генерирует событие. CLR хранит список активных таймеров, их объект делегата обратного вызова сохраняет ссылку на Timer.

  • Обработчиком событий Elapsed, если он не является статическим. Это продлевает время жизни экземпляра Timer по крайней мере до времени жизни объекта класса, содержащего обработчик события Elapsed.

Здесь нет режима отказа. Единственный возможный способ получить ссылку на таймер — через аргумент sender обработчика Elapsed события. Если вы отключите таймер, больше не будет способа получить ссылку, поэтому он подходит для сбора объекта.

Довольно классический способ получить проблемы с этим таймером и потерять прошедшие события — это когда у вас есть свойство AutoReset, установленное в false. Очень неприятная проблема заключается в том, что любые исключения, возникающие в обработчике событий Elapsed, проглатываются без какой-либо диагностики. Что позволит обойти вызов, который вам придется перезапустить таймер в конце. Отдавайте предпочтение System.Threading.Timer, у него нет этой проблемы.

person Hans Passant    schedule 10.02.2011
comment
+1. Знаете ли вы, почему System.Threading.Timer без ссылки может быть GC'ed, но не System.Timers.Timer? - person Stephen Cleary; 10.02.2011
comment
@Стивен, не уверен, что ты имеешь в виду. Те же правила, список активных таймеров внутри CLR, обратный вызов ссылается на целевой объект. А несвязанный System.Timers.Timer может быть собран, если он не включен. - person Hans Passant; 10.02.2011
comment
Мой периодический System.Threading.Timer без ссылок проходит GCed, а мой System.Timers.Timer без ссылок с автоматическим сбросом - нет. Обработчик событий не ссылается на таймер. Можешь подтвердить? (Клиент .NET 4.0) - person Stephen Cleary; 10.02.2011
comment
@Стивен - это совсем другой вопрос. Почему бы вам не начать свой собственный? Пожалуйста, предоставьте доказательства того, как вы узнали, что они не собираются. - person Hans Passant; 10.02.2011
comment
stackoverflow.com/questions/4962172/ - person Stephen Cleary; 10.02.2011
comment
С помощью обработчика события Elapsed, если он не является статическим – поясните это утверждение. Потому что кажется, что вы говорите, что обработчик каким-то образом сохраняет ссылку на таймер, делая его доступным и предотвращая GC. Это отличается от того, что происходит на самом деле: объект публикации события сохраняет ссылку на обработчик, который может поддерживать этот объект в рабочем состоянии. Но он не поддерживает таймер в рабочем состоянии, за исключением любого короткого периода времени, в течение которого обработчик фактически выполняется (поскольку ссылка на таймер передается в качестве параметра). ... - person Peter Duniho; 12.10.2019
comment
... По иронии судьбы, вы предлагаете System.Threading.Timer, который представляет собой реализацию таймера, в которой вы должны явно сохранить ссылку на правило таймера, чтобы предотвратить его GC. Он просто меняет одну ловушку, в которую легко попасть, на другую. :( - person Peter Duniho; 12.10.2019

да. Timer будет GC'ирован, если не ссылаться на него, даже во время работы.

В документации говорится:

Код содержит объявления переменной таймера на уровне класса и внутри Main. Чтобы увидеть, как агрессивная сборка мусора может повлиять на таймер, объявленный внутри долго выполняющегося метода, вы можете закомментировать объявление уровня класса и раскомментировать локальную переменную. Чтобы таймер не собирался, раскомментируйте метод GC.KeepAlive в конце Main.

person SLaks    schedule 10.02.2011
comment
Нет, это было исправлено в .NET 2.0. Попробуй. - person Hans Passant; 10.02.2011
comment
Тогда документы нужно исправить: msdn.microsoft.com/en- us/library/system.timers.timer.aspx составляет около 4,5 - person Henk Holterman; 06.08.2013
comment
Текущая документация, похоже, удалила это ошибочное утверждение. - person Peter Duniho; 12.10.2019