Согласно MSDN, ссылка на System.Threading.Timer должна храниться в противном случае, она получит сбор мусора. Так что, если я запускаю этот код, он не пишет никаких сообщений (что ожидаемое поведение):C# Таймеры и сбор мусора
static void Main(string[] args)
{
RunTimer();
GC.Collect();
Console.ReadKey();
}
public static void RunTimer()
{
new Timer(s => Console.WriteLine("Hello"), null, TimeSpan.FromSeconds(1), TimeSpan.Zero);
}
Однако, если я немного изменить код, храня таймера во временной локальной переменной, она выживает и пишет сообщение:
public static void RunTimer()
{
var timer = new Timer(s => Console.WriteLine("Hello"));
timer.Change(TimeSpan.FromSeconds(1), TimeSpan.Zero);
}
Во время сбора мусора, там, видимо, нет способа, как получить доступ к таймеру от корня или статических объектов. Так вы можете объяснить, почему таймер выживает? Где сохраняется эта ссылка?
Это обязательно * используется * чтобы быть правдой. Похоже, что Microsoft наконец-то что-то с этим поделала, тысячи вызовов поддержки должны были вдохновлять. Не уверен, когда это произошло, где-то около 4.5 или 4.6 я подозреваю. Теперь они сохраняются в живых, поскольку они тикают, [TimerQueue.s_queue] (http://referencesource.microsoft.com/#mscorlib/system/threading/timer.cs,75523a07eb2de983) позаботится об этом. –
Спасибо, но нужно ли сохранять таймер в обоих сценариях? Почему он выживает только второй? Я запускаю .NET 4.6.1. –
Это похоже на ошибку. Только метод Change() получает таймер, добавленный в очередь таймера, конструктор забывает это сделать. Довольно трудно представить, что это было намеренно, подумайте об этом. –