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

Dav*_*huu 1 .net c# 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>
Run Code Online (Sandbox Code Playgroud)

代码隐藏是:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道的一些事实:

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

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

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

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

Han*_*ant 9

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

这使GC保持参考,直到你停止计时器.您只能通过转换发送者参数在事件处理程序中执行此操作,只能自行获取引用.

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

  • 在这篇文章之前,泄漏的可能性非常重要,而不是我所知道的.要小心! (2认同)