为什么我看到"你好"在发布模式下将 timer.Dispose()添加到我的代码中的次数很多次。如果没有 timer.Dispose(),我会看到" Hello"一旦。谢谢。
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Method(object state)
{
Console.WriteLine(state);
GC.Collect();
}
static void Main()
{
var timer = new Timer(Method, "Hello", 0, 200);
Console.ReadLine();
timer.Dispose();
}
}
}
答案 0 :(得分:3)
你看到它一次,因为垃圾收集器已经收集了计时器对象。
由于没有更多被称为“实时”的引用,垃圾收集器可以自由地进行。
在发布模式下,当没有附加调试器时,JITter会建立有关方法中局部变量使用位置的知识。一旦变量不再使用,如果该方法当前正在该点之下执行,则不再将其视为根。这样,垃圾收集器可以收集计时器对象。但是,在它可以这样做之前,它必须完成对象,它会破坏底层的计时器对象并阻止它执行。
在调试版本中,所有局部变量的范围都被人为地扩展为整个方法,因此如果在方法中放置断点,则可以检查变量,即使程序实际上不再需要该变量存在
当您添加对dispose的调用时,您延长了变量的生命周期,从而阻止了垃圾收集器收集您的计时器对象。
由于您在计时器事件处理程序方法中引发了垃圾收集,因此在这种情况下您可以自己销毁计时器。通过添加对Dispose的调用来扩展变量的生命周期时,垃圾收集器仍然作为计时器事件处理程序的一部分运行,但它还无法收集计时器,因此它会一直运行。
Hans Passant留下的答案比我上面的微薄尝试要好得多:
答案 1 :(得分:0)
我怀疑它是因为GC.Collect
在timer
对象仍然被引用到当前代码行之下时不会收集它。
timer.Dispose();
的行为与GC.KeepAlive(timer);
类似。
如果同时删除Dispose
和GC.Collect()
,您将获得一些" Hello" s,然后GC将决定自行收集,而您#&# 39;不再有了。