C#定时器和垃圾收集

时间:2016-06-07 14:02:28

标签: c# .net timer garbage-collection

根据MSDN,应该保留对System.Threading.Timer的引用,否则它将被垃圾收集。因此,如果我运行此代码,它不会写任何消息(这是预期的行为):

[{1 => 30}, {2 => 20}] 

但是,如果我通过将计时器存储在临时局部变量中来略微修改代码,它会幸存并写入消息:

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);
}

在垃圾收集期间,显然无法从根或静态对象访问计时器。所以你能解释为什么计时器存活下来吗?保留的参考在哪里?

1 个答案:

答案 0 :(得分:4)

每个Timer引用TimerHolder,引用TimerQueueTimer。该实现通过调用UpdateTimer()保留对TimerQueueTimer的内部引用。

在正常情况下,您的计时器可以免费收集,finalizing the TimerHolder并从内部队列中删除TimerQueueTimer。但是简单的构造函数Timer(TimerCallback) calls TimerSetup()以及Timer本身作为状态。因此,在这种特殊情况下,TimerQueueTimer的状态会引用Timer,从而阻止其被收集。

效果与保持临时局部变量无关。由于Timer机制的内部原因,恰好才能工作。按照MSDN的建议,保持对计时器的引用更加清晰和安全。