在C#中,我应该把计时器放在哪里';谁的推荐信?
在C#中,我应该把计时器放在哪里';谁的推荐信?,c#,.net,garbage-collection,reference,timer,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 MyStateO
System.Threading.Timer
的文档说我应该为它保留一个实时引用,以避免它被垃圾收集。但是我应该在哪里做呢?我的main
非常简单,我不知道在哪里保存引用:
class Program {
static void Main() {
new System.Threading.Thread(myThreadStart).Start();
new System.Threading.Timer(myTimerCallback, new MyStateObject(), 0, 5000);
}
}
我考虑将引用保存在
程序
类的静态
字段中,假设静态
字段在应用程序结束之前不会被收集。但是我不确定这是最好的方法,所以我很感激你的建议。编辑:我最初的答案是垃圾。真是垃圾。我把它放在这里是为了解释为什么它是垃圾——虽然它在评论中,但是它们已经被删除了,答案也一样
在调用之前,GC.KeepAlive仅确保引用被视为根。在这个答案底部的代码中,将立即调用GC.KeepAlive方法,然后计时器仍然可以进行垃圾收集。因为新创建的线程是一个前台线程,所以应用程序将一直运行(而计时器使用后台线程,这不会阻止程序退出)。这意味着主方法退出,但应用程序需要保持运行
可以说,一个更简单的解决方案是在主线程中运行myThreadStart
,而不是创建一个新线程,然后让主线程死掉。换句话说,一个简单的解决方案是:
using System.Threading;
class Program {
static void Main() {
Timer timer = new Timer(myTimerCallback,
new MyStateObject(), 0, 5000);
myThreadStart();
GC.KeepAlive(timer);
}
}
但我假设实际代码更复杂——在这种情况下,使用其他答案中建议的私有静态变量可能是一种方法。不过,这将取决于使用情况。我个人不喜欢创建一个静态字段,只是为了防止在有其他方法(如上面所述)的情况下收集某些内容,但有时这实际上是唯一的方法
原始(错误)答案:
如果您确实想在Main中分配它,那么您可以使用:
我认为可以保留您的类的私有静态字段
我会将此引用保留为静态字段,而不是使用垃圾收集器。如果计时器是应用程序级对象,将其作为主类的私有静态成员没有什么错。无论如何,我都会这么做。谢谢。根据KeepAlive的文档,它“引用了指定的对象,这使得它从当前例程开始到调用此方法为止都不符合垃圾收集的条件。”这难道不意味着,在主方法结束时,该对象可以是GC'd?@Hosam-您需要保留main()方法仍然处于活动状态-从该方法返回将终止您的程序。@Michael Burr,当通过(新踏板…)创建的线程正在运行时,程序将不会退出。@Michael,是的,您是对的,我在写问题后注意到了这一点@阿库,你也对,我刚试过。谢谢大家。@Hosam Aly,现在你需要点击正确答案附近的“接受”按钮:)谢谢。我猜垃圾收集器不会收集静态字段,即使它是私有的(并且不再被访问),是吗?基本上有两种方法会导致类似的结果-在程序运行时不会收集对计时器的引用(即,您通过new thread.创建的线程处于活动状态)。我猜您可能希望删除“GC.KeepAlive”根据Jon Skeet澄清后的回答:你能在回答中提供一个例子吗?在类作用域中声明计时器会阻止GC,不是吗?
using System.Threading;
class Program {
static void Main() {
new Thread(myThreadStart).Start();
Timer timer = new Timer(myTimerCallback,
new MyStateObject(), 0, 5000);
GC.KeepAlive(timer);
}
}