在 C# 中,我应该将计时器的引用保存在哪里?

Posted

技术标签:

【中文标题】在 C# 中,我应该将计时器的引用保存在哪里?【英文标题】:In C#, where should I keep my timer's reference? 【发布时间】:2009-01-25 07:57:21 【问题描述】:

System.Threading.Timer 的文档说我应该为它保留一个实时引用以避免它被垃圾收集。但是我应该在哪里做呢?我的main很简单,不知道在哪里放参考:

class Program 
    static void Main() 
        new System.Threading.Thread(myThreadStart).Start();
        new System.Threading.Timer(myTimerCallback, new MyStateObject(), 0, 5000);
    

我考虑将引用保存在Program 类的static 字段中,假设static 字段直到应用程序结束才被收集。但我不确定这是不是最好的方法,所以我很感激你的建议。

【问题讨论】:

【参考方案1】:

如果您的 Timer 是应用程序级别的对象,那么将其设置为 Main 类的私有静态成员没有任何问题。无论如何,这就是我会做的。

【讨论】:

能否在您的回答中提供一个样本 在类范围内声明定时器也会阻止GC不是吗?【参考方案2】:

编辑:我原来的答案是垃圾。真的很垃圾。我把它放在这里是为了解释为什么虽然它是垃圾 - 它在 cmets 中,但它们会随着答案被删除。

GC.KeepAlive 仅确保在调用之后引用被视为根。在此答案底部的代码中,将立即调用 GC.KeepAlive 方法,然后计时器仍然有资格进行垃圾收集。因为新创建的线程是前台线程,所以只要它还活着,应用程序就会运行(而计时器使用后台线程,这不会阻止程序退出)。这意味着 Main 方法退出,但应用程序需要继续运行。

可以说一个更简单的解决方案是在主线程中运行myThreadStart,而不是创建一个新的然后让主线程死掉。换句话说,一个简单的解决方案是:

using System.Threading;

class Program 
    static void Main() 
        Timer timer = new Timer(myTimerCallback, 
                                new MyStateObject(), 0, 5000);
        myThreadStart();
        GC.KeepAlive(timer);
    

我认为 real 代码更复杂 - 在这种情况下,使用其他答案中建议的私有静态变量可能是要走的路。不过,这确实取决于使用情况。如果有替代方案(如上述),我个人不希望仅仅为了防止收集某些内容而创建静态字段,但有时它实际上是唯一的方法。

原始(错误)答案:

如果你真的想在Main中分配它,那么你可以使用GC.KeepAlive:

using System.Threading;

class Program 
    static void Main() 
        new Thread(myThreadStart).Start();
        Timer timer = new Timer(myTimerCallback, 
                                new MyStateObject(), 0, 5000);
        GC.KeepAlive(timer);
    

【讨论】:

谢谢。根据 KeepAlive 的文档,它“引用了指定的对象,这使得它没有资格从当前例程开始到调用此方法的位置进行垃圾收集”。这不是说,在main方法结束时,对象就可以被GC了吗? @Hosam - 无论如何,您都需要保持 Main() 方法处于活动状态 - 从它返回将终止您的程序。 @Michael Burr,当通过 (new Tread...) 创建的线程正在运行时,程序不会退出。 @Michael,是的,你是对的,我注意到在我写完这个问题之后。 @aku,你也是对的,我刚试过。谢谢大家。 @Hosam Aly,现在你需要点击正确答案附近的“接受”按钮:)【参考方案3】:

我认为保留类的 私有静态 字段是可以的。

我会将此引用保留为静态字段,而不是使用垃圾收集器。

【讨论】:

谢谢。我猜垃圾收集器不会收集静态字段,即使它是私有的(不再访问),对吗? 基本上两种方法会导致相似的结果 - 在您的程序运行时不会收集对计时器的引用(即您通过 new Thread.. 创建的线程是活动的)。 我猜你可能想在 Jon Skeet 的澄清之后从你的答案中删除“GC.KeepAlive”。 :)

以上是关于在 C# 中,我应该将计时器的引用保存在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

保存计时器高分

C# - 在需要时从多个运行的计时器中处理一个特定的计时器[关闭]

Timer 计时器 (SwiftUI中文文档手册)

计时器每秒触发一次并更新 GUI(C# Windows 窗体)

如何在 C# 中重置计时器?

Angular 4预定表单自动保存