未引用的活动DispatcherTimer和垃圾收集器

时间:2014-08-26 16:15:14

标签: c# .net wpf garbage-collection

我有以下XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:self="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label Name="lblTime" FontSize="48" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</Window>

代码隐藏是:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DispatcherTimer timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += timer_Tick;
        timer.Start();
        GC.Collect();
    }
    void timer_Tick(object sender, EventArgs e)
    {
        lblTime.Content = DateTime.Now.ToLongTimeString();
        GC.Collect();
    }
}

我知道的一些事实:

  • 即使.NET垃圾收集器是一个不确定的垃圾收集器,也可以通过GC.Collect()
  • 的调用来强制收集。
  • 收集完成后,任何未引用的对象都会被销毁

在代码隐藏中,MainWindow不会对计时器进行任何引用。在我看来,它应该被销毁,界面不应该再更新,因为我放了一些GC.Collect调用。但似乎它不起作用,因为界面仍在更新,因此,对象仍然存在。

问题是:发生了什么?我错了吗?还是我错过了一些重要的事实?

编辑1 :此代码实际上是我在教程中找到的一个示例,显示了如何使用DispatcherTimer。但是我想知道当垃圾收集开始时会发生什么,这就是为什么我添加那些GC.Collect以便看看会发生什么。感谢我读过的关于.NET GC的大量教程,我知道调用GC.Collect是一个坏主意,除非非常特殊,否则不应该这样做。

1 个答案:

答案 0 :(得分:9)

Dispatcher类为活动计时器维护内部List<DispatcherTimer>。内部Dispatcher.AddTimer()方法添加它,在Start()方法上调用。 RemoveTimer()由Stop​​()方法调用。

这会让GC看到参考,直到你停止计时器。您只能通过转换 sender 参数在事件处理程序中执行此操作,只能自行获取引用。

请记住,如果您不调用Stop(), 会继续滴答滴答,即使关闭了具有定时器事件处理程序的Window也是如此。如果你不这样做,那么这样的窗口对象就会泄漏,只有你幸运的话,你才会得到一个ObjectDisposedException。