在C#中,我应该在哪里保留计时器的参考?

时间:2009-01-25 07:57:21

标签: c# .net garbage-collection reference timer

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

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

我考虑将引用保留在static类的Program字段中,假设在应用程序结束之前不会收集static字段。但我不确定这是最好的方法,所以我很感激你的意见。

3 个答案:

答案 0 :(得分:18)

如果你的Timer是一个应用程序级别的对象,那么将它作为Main类的私有静态成员是没有错的。无论如何,这就是我要做的。

答案 1 :(得分:12)

编辑:我原来的答案是垃圾。真的很垃圾。我一直在这里解释为什么它仍然是垃圾 - 它在评论中,但它们已被删除了答案。

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);
    }
}

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

原创(不好)回答:

如果您真的想在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);
    }
}

答案 2 :(得分:4)

我认为保持是您班级的私有静态字段是可以的。

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