C# 中有三种定时器,
System.Windows.Forms
中的定时器和
System.Timers.Timer
的工作方式是完全一样的,所以,这里我们仅讨论
System.Timers.Timer
和
System.Threading.Timer
1、定时器保活
先来看一个例子:
运行结果如下:
在
Start
方法结束后,
Foo
实例已经失去了作用域,按理说应该被回收,但实际并没有(因为析构函数没有执行,所以肯定实例未被回收)。
这就是定时器的
保活机制
,因为定时器需要执行
timer_Elapsed
方法,而该方法属于
Foo
实例,所以
Foo
实例被保活了。
但多数时候这并不是我们想要的结果,这种结果导致的结果就是
内存泄露
,解决方案是:先将定时器
Dispose
。
一个很好的准则是:如果类中的任何字段所赋的对象实现了
IDisposable
接口,那么该类也应当实现
IDisposable
接口。
在这个例子中,不止
Dispose方法,Stop方法和设置AutoReset = false,都能起到释放对象的目的。但是如果在Stop方法之后又调用了Start方法,那么对象依然会被保活,即便Stop之后进行强制垃圾回收,也无法回收对象。
System.Timers.Timer
和
System.Threading.Timer
的保活机制是类似的。
保活机制是由于定时器引用了实例中的方法,那么,如果定时器不引用实例中的方法呢?
2、不保活下
System.Timers.Timer
和
System.Threading.Timer
的差异
要消除定时器对实例方法的引用也很简单,将
timer_Elapsed
方法改成
静态
的就好了。(静态方法属于类而非实例。)
改成静态方法后再次运行示例,结果如下:
Foo
实例是被销毁了(析构函数已运行,打印出了 End),但定时器还在执行,这是为什么呢?
这是因为,.NET Framework 会确保
System.Timers.Timer
的存活,即便其所属实例已经被销毁回收。
如果改成
System.Threading.Timer
,又会如何?