为什么GC无法弄清楚?



我的问题很简单,为什么GC不能弄清楚main中的timer对象应该与TestTimer中的timer和相关的EventHandler一起被垃圾收集?

为什么我不断得到console.Writeline输出?

class Program
{
    public static void Main()
    {       
       TestTimer timer = new  TestTimer();
       timer = null;
       GC.Collect();
       GC.WaitForPendingFinalizers();
       Console.ReadKey();
    }
}
public class TestTimer
{
    private Timer timer;
    public TestTimer()
    {
        timer = new Timer(1000);
        timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
        timer.Start();
    }
    private void timer_Elapsed(Object sender, ElapsedEventArgs args)
    {
        Console.Write("n" + DateTime.Now);
    }
}

不要依赖于GC,使用Dispose模式来正确地处置TestTimer(然后应该处置Timer)。

然而,发生的情况是定时器通过获取自身的GC句柄来保持自身存活。阅读这篇博文:

http://nitoprograms.blogspot.com/2011/07/systemthreadingtimer-constructor-and.html?utm_source=feedburner& utm_medium = feed& utm_campaign =提要% 3 + blogspot % 2 folztt + % 28 nito +编程% 29日

为什么您首先期望可以收集活动计时器?我的期望是它充当GC根。否则计时器会停止工作,因为你不再有一个引用。

您没有在使用后处理计时器。这就是延迟其收集的原因。

如果你的类包含实现IDisposable的对象(就像Timer一样),它也应该实现IDisposable

public class TestTimer : IDisposable
{
    private Timer timer;
    public TestTimer()
    {
        timer = new Timer(1000);
        ...
    }
    #region IDisposable
    public void Dispose()
    {
        Dispose(true);
    }
    volatile bool disposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (disposing && !disposed)  
        {
            timer.Dispose();
            GC.SupressFinalize(this);
            disposed = true;
        }
    }
    ~TestTimer() { Dispose(false); }
    #endregion
}

你的主方法应该是这样的:

public static void Main()
{       
   using (TestTimer timer = new  TestTimer())
   {
       // do something
   }
   GC.Collect();
   GC.WaitForPendingFinalizers();
   Console.ReadKey();
}

同样,如果你的TestTimer应该比单个Main方法的作用域更长,那么创建它并保存它的引用的类也应该实现IDisposable

当你启动定时器timer.Start()时,一个新线程将在后台启动,当你调用timer = null;时,你并没有停止计时器使用的线程。无论创建这些线程的原始对象是什么,垃圾收集器都不会杀死或中止正在运行的线程。

事实证明,这个状态参数(和TimerCallback委托)对垃圾收集有一个有趣的影响:如果它们都没有引用System.Threading.Timer对象,它可能被垃圾收集,导致它停止。这是因为TimerCallback委托和状态参数都被包装到一个GCHandle中。如果它们都没有引用计时器对象,则它可能符合GC的条件,从而将GCHandle从其终结器中释放出来。

相关内容

  • 没有找到相关文章

最新更新