15

的文档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在应用程序结束之前不会收集这些字段。但我不确定这是最好的方法,所以我很感激你的建议。

4

3 回答 3

18

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

于 2009-01-25T08:58:39.200 回答
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);
    }
}
于 2009-01-25T07:59:57.230 回答
4

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

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

于 2009-01-25T08:01:57.070 回答