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

发布于 2024-12-17 14:06:10 字数 804 浏览 2 评论 0原文

可能的重复:
计时器、事件和垃圾收集:我错过了什么吗?

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

╰つ倒转 2024-12-24 14:06:10

您需要了解 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 跟踪它时,您可以看到上面参考链中的“System”通过标记为 的 TimerBase.AddTimerNative 方法发挥作用MethodImplOptions.InternalCall 因此我们无法准确地看到引用是如何扎根于这一点以下的。但是,它仍然扎根了。

如果您通过 Enabled = falseStop 禁用计时器,那么它将处置底层的 System.Threading.Timer ,而后者又应该停止引用System.Timers.Timer

You need to understand what System.Timers.Timer is doing behind the scenes. It is a wrapper around the System.Threading.Timer class. When the timer starts it creates a new System.Threading.Timer instance and passes it a callback method in the System.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 the Elapsed event handler will not solve this problem because that delegate only holds a reference to the TrayForm instance. Again, it is the System.Threading.Timer that is keeping a reference to the System.Timers.Timer. The whole reference chain remains rooted because the system has to reference the System.Threading.Timer for it to work.

Here is the reference chain:

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

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 marked MethodImplOptions.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 or Stop then it will dispose the underlying System.Threading.Timer which should in turn stop referencing the System.Timers.Timer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文