简体   繁体   English

C#定时器和垃圾收集

[英]C# Timers and Garbage Collection

According to MSDN , a reference to System.Threading.Timer should be kept otherwise it will get garbage-collected. 根据MSDN ,应该保留对System.Threading.Timer的引用,否则它将被垃圾收集。 So if I run this code, it doesn't write any message (which is the expected behavior): 因此,如果我运行此代码,它不会写任何消息(这是预期的行为):

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

However, if I modify the code slightly by storing the timer in a temporary local variable, it survives and writes the message: 但是,如果我通过将计时器存储在临时局部变量中来稍微修改代码,它会幸存并写入消息:

public static void RunTimer()
{
    var timer = new Timer(s => Console.WriteLine("Hello"));
    timer.Change(TimeSpan.FromSeconds(1), TimeSpan.Zero);
}

During garbage collection, there is apparently no way how to access the timer from root or static objects. 在垃圾收集期间,显然无法从根或静态对象访问计时器。 So can you please explain why the timer survives? 所以你能解释为什么计时器存活下来吗? Where is the reference preserved? 保留的参考在哪里?

Each Timer references a TimerHolder , which references a TimerQueueTimer . 每个Timer引用一个TimerHolder ,它引用一个TimerQueueTimer The implementation keeps an internal reference to the TimerQueueTimer via the call to UpdateTimer() . 该实现通过调用TimerQueueTimer UpdateTimer()保持对TimerQueueTimer的内部引用。

Under normal circumstances your timer is free to be collected, finalizing the TimerHolder and removing the TimerQueueTimer from the internal queue. 在正常情况下,您的计时器可以自由收集, 最终确定TimerHolder并从内部队列中删除TimerQueueTimer But the simple constructor Timer(TimerCallback) calls TimerSetup() with the Timer itself as the state. 但是简单的构造函数Timer(TimerCallback) TimerSetup()Timer本身作为状态调用TimerSetup() So in this particular case, the TimerQueueTimer 's state references back to the Timer , preventing it from being collected. 因此在这种特殊情况下, TimerQueueTimer的状态会引用回Timer ,从而阻止它被收集。

The effect is not related to keeping a temporary local variable. 效果与保持临时局部变量无关。 It just so happens to work due to the internals of the Timer mechanism. 由于Timer机制的内部原因,它恰好正常工作。 It is much clearer and safer to keep a reference to your timer as recommended by MSDN. 按照MSDN的建议,保持对计时器的引用更清晰,更安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM