为什么本地捕获的计时器不会超出范围?

时间:2011-11-22 14:58:06

标签: c# timer garbage-collection capture

  

可能重复:
  Timer, event and garbage collection : am I missing something?

private void TrayForm_Load(object sender, EventArgs e)
{
    System.Timers.Timer HideMeTimer = new System.Timers.Timer(2500);
    HideMeTimer.Elapsed +=  
        delegate(object sender2, System.Timers.ElapsedEventArgs e2)
        {
            this.Invoke(new Action(somestuff));
        };
        HideMeTimer.Start();
        GC.Collect();
}

有人可以告诉我编译器将如何翻译吗? 或者很好地解释为什么定时器在加载事件后继续滴答作响。

(当最后一个引用消失时,不是规则,变量,GC会在某个时间 杀死对象!)

1 个答案:

答案 0 :(得分:12)

您需要了解System.Timers.Timer在幕后所做的事情。它是System.Threading.Timer类的包装器。当计时器启动时,它会创建一个新的System.Threading.Timer实例,并在System.Timers.Timer实例中传递一个回调方法。只要计时器保持启用状态,系统就会引用此回调委托。

我们也知道委托保留对包含目标方法的类的实例的引用。这就是为什么没有收集System.Timers.Timer实例并且不会自动停止的原因。删除Elapsed事件处理程序不会解决此问题,因为 委托仅保存对TrayForm实例的引用。同样,System.Threading.Timer保留了对System.Timers.Timer的引用。整个参考链仍然是根的,因为系统必须引用System.Threading.Timer才能使其工作。

以下是参考链:

System => _TimerCallback => Callback => System.Threading.Timer => Callback => System.Timers.Timer

当您使用Reflector或ILSpy跟踪此信息时,您可以看到上面参考链中的“系统”通过标记为TimerBase.AddTimerNative的{​​{1}}方法发挥作用,因此我们无法确切了解引用根植于此点之下。但是,它仍然是根深蒂固的。

如果您通过MethodImplOptions.InternalCallEnabled = false停用了计时器,那么它将处置基础Stop,而System.Threading.Timer又会停止引用System.Timers.Timer