如何解决本地范围的计时器的预期行为是什么?
| 具体来说,如果您在本地范围内创建一个Timer实例,然后从该范围返回: 1)计时器仍会执行吗? 2)什么时候会被垃圾收集? 我提供以下两种情况:Timer timer = new Timer(new TimerCallback((state) => { doSomething(); }));
timer.Change((int)TimeSpan.FromSeconds(30),(int)TimeSpan.FromSeconds(30));
return;
和
Timer timer = new Timer(new TimerCallback((state) => { doSomething(); }));
timer.Change((int)TimeSpan.FromSeconds(30),Timeout.Infinite);
return;
解决方法
TimerCallback
引用了方法DoSomething()
,因此(在您的示例中)引用了this
,但是没有实时引用,因此应该将其收集起来...最终
, 计时器是否执行,取决于垃圾收集是否在时间执行之前运行。这就是为什么优良作法是在堆栈上以外的地方保留对计时器的引用。
注意,这并不总是有问题的。例如,只要线程仍在运行,就不会收集它们。
, 这是一个快速测试:
class Program
{
static void Main(string[] args)
{
Something something = new Something();
Foo(something);
Console.ReadKey(true);
GC.Collect();
Console.ReadKey(true);
}
private static void Foo(Something something)
{
Timer timer = new Timer(new TimerCallback(something.DoIt),null,5);
return;
}
}
public class Something
{
public void DoIt(object state)
{
Console.WriteLine(\"foo{0}\",DateTime.Now.Ticks);
}
}
从本质上讲,这就是编译器将其炸破的内容(您的示例中的Lambda表达式)。运行此命令时,您会发现,只要您不按第一个键,它就会一直将内容放到控制台上。按下键后,GC就会启动,它会停止。 Timer
仍然引用Something
,但是没有任何引用Timer的说明,因此它消失了。
, 如果您在谈论System.Threading.Timer
,它实现了IDisposable
,因此您应该维护对它的引用,以便在不再使用它时可以调用Dispose。我不知道您的特定问题的答案,但是您可以在控制台应用程序中运行多次迭代并强迫GC.Collect()
来查看Timer是否继续启动,以对其进行调查。我的猜测是,除非在内部创建了一些基于静态的引用,否则它将最终被收集并停止触发。
附带说明一下,如果您想要一个一次性“即弃即忘”计时器,则可以通过创建一个引用了Timer的状态对象来实现一个计时器,这样,在计时器事件触发时,它就可以自行处置。我有一个使用此模式的WhenElapsed(TimeSpan,Action)
方法的TimerService
类,它非常方便创建超时,而不必将Timer实例作为包含类中的字段进行管理。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。