为什么本地捕获的计时器不会超出范围?
可能的重复:
计时器、事件和垃圾收集:我错过了什么吗?
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有时会 杀死物体!)
Possible Duplicate:
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();
}
Can somebody please show me how the compilator will translate this?
Or good explanation why the timer keep on ticking after the load event.
(Is not the rule when the last reference is gone, to an variable, the GC will sometime
kill the object !)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要了解 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
才能工作。这是参考链:
当您使用 Reflector 或 ILSpy 跟踪它时,您可以看到上面参考链中的“System”通过标记为
的 TimerBase.AddTimerNative 方法发挥作用MethodImplOptions.InternalCall
因此我们无法准确地看到引用是如何扎根于这一点以下的。但是,它仍然扎根了。如果您通过
Enabled = false
或Stop
禁用计时器,那么它将处置底层的System.Threading.Timer
,而后者又应该停止引用System.Timers.Timer
。You need to understand what
System.Timers.Timer
is doing behind the scenes. It is a wrapper around theSystem.Threading.Timer
class. When the timer starts it creates a newSystem.Threading.Timer
instance and passes it a callback method in theSystem.Timers.Timer
instance. The system references this callback delegate as long as the timer remains enabled.We also know that delegates keep a reference to an instance of the class containing the target method. This is why your
System.Timers.Timer
instance is not collected and does not stop automatically. Removing theElapsed
event handler will not solve this problem because that delegate only holds a reference to theTrayForm
instance. Again, it is theSystem.Threading.Timer
that is keeping a reference to theSystem.Timers.Timer
. The whole reference chain remains rooted because the system has to reference theSystem.Threading.Timer
for it to work.Here is the reference chain:
When you track this through with Reflector or ILSpy you can see that the "System" in the reference chain above comes into play via the
TimerBase.AddTimerNative
method which is markedMethodImplOptions.InternalCall
so we cannot see exactly how the reference is rooted below this point. But, it is rooted nonetheless.If you disable the timer via
Enabled = false
orStop
then it will dispose the underlyingSystem.Threading.Timer
which should in turn stop referencing theSystem.Timers.Timer
.