本地范围的计时器的预期行为是什么?

问题描述

| 具体来说,如果您在本地范围内创建一个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实例作为包含类中的字段进行管理。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...