System.Timers.Timer 生命周期

3

如何正确使用System.Timers.Timer? 我的意思是......我创建了计时器,设置了间隔和在Elapsed事件上调用的方法。

double ms = 1000;
var t = new System.Timers.Timer(ms);
t.AutoReset = false;
t.Elapsed += (sender, e) =>  { runTask(); }; 
t.Start();   

下一步该怎么办?调用计时器的Dispose方法吗?我想我不能这样做,否则Elapsed事件将永远不会发生。 我应该在某个全局变量中注册计时器,以避免失去对它的引用,这样GC在调用Elapsed之前就可以处理掉计时器了吗? 如果是这样,那么一旦处理完Elapsed事件(也就是完成任务),我该如何处理计时器的Dispose方法呢?
3个回答

4
如果您在长时间运行的过程(例如Web应用程序或Windows服务)中使用计时器,如果您不想出现内存泄漏,您需要确保在希望垃圾回收器能够回收为计时器对象分配的内存时,取消订阅计时器的已过去事件处理程序。
System.Timers.Timer实现了IDisposable接口,根据指南,如果您有一个实现IDisposable的类,那么任何依赖于实现IDisposable的对象的类也应该实现IDisposable并在其被调用时调用对象的Dispose()方法。
这个完美的例子就是System.Timers.Timer。它在内部使用System.Threading.Timer,如果您查看反射器,您可以看到System.Timers.Timer的Dispose方法的以下内容。
public void Dispose()
{
    this.timerBase.Dispose();
}

在这里,timerBase只是System.Threading.Timer的一个实例,因此Dispose调用会级联到实现IDisposable接口的类的所有依赖项。


1
简短的回答是你不需要做任何事情。当函数超出范围时,它将被垃圾收集器收集。如果您希望其可用,请在类中声明它。
通常,当您在类级别上声明计时器时,当类被处理时,它会被GC收集。但是,当您在函数中声明计时器时,计时器仍在运行,但如果您执行非常长的过程,则GC可能会积极地处理它,因此您需要使用
GC.KeepAlive(youtimer_Instance);

请查看计时器文档的末尾,以获取有关此场景的参考。

示例代码中的注释如下:


        通常,计时器在类级别上声明,
        这样它就可以在需要的时间内保持范围。
        如果计时器在长时间运行的方法中声明,
        必须使用KeepAlive来防止JIT编译器在方法结束之前允许
        进行激进的垃圾回收。

如果定时器是在表单A上创建的,且用户退出应用程序(如果任务尝试访问表单控件,则会引发异常,我曾经遇到过这种情况),可能会出现问题。 - Mohib Sheth
@Mohib Sheth:我回答的是如何保护计时器不被释放...要停止它,显然需要调用Stop()。如果需要的话,最好取消订阅事件处理程序。Alexis已经解释过了... - Shekhar_Pro
顺便说一下,你引用的代码注释在计时器文档中已经不存在了。 - Neil

0

在您的表单/页面的Close/Unload或任何您认为合适的地方调用t.Stop()。如果让它继续运行,它将不必要地占用资源,并且在关闭应用程序时可能会出现异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接