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

本文关键字:收集器 DispatcherTimer 引用 活动 | 更新日期: 2023-09-27 18:19:32

我有以下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调用。但它似乎不起作用,因为接口仍在更新中,因此对象仍然存在。

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

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

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

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

这样GC就可以看到一个引用,直到您停止计时器。这只能在事件处理程序中通过强制转换sender参数来完成,这是您自己获取引用的唯一方法。

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