【问题标题】:Garbage collection of C# object declared in constructor在构造函数中声明的 C# 对象的垃圾收集
【发布时间】:2011-08-31 14:15:44
【问题描述】:

在下面的代码中,我在类的构造函数中创建了一个 DispatcherTimer。没有人继续引用它。

在我的理解中,定时器应该在离开构造函数作用域后的某个时间被垃圾收集器回收。 但这不会发生!即使在使用 GC.Collect() 强制进行垃圾回收之后

幕后发生了什么?

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        new DispatcherTimer
        {
            Interval = TimeSpan.FromMilliseconds(100),
            IsEnabled = true
        }
        .Tick += (s, e) =>
        {
            textBlock1.Text = DateTime.Now.ToString();
        };
    }
}

【问题讨论】:

    标签: c# .net constructor garbage-collection


    【解决方案1】:

    定时器相当特别,因为它们通过调用来根植自己

    this.timerRoot = GCHandle.Alloc(this);
    

    一些链接

    编辑:

    没有意识到它是一个DispatcherTimer - 它不会直接根植于自己,而是间接地(到Dispatcher),这反过来会导致相同的效果......

    【讨论】:

    • DispatcherTimers 是否遵守与 Threading.Timers 相同的垃圾收集规则?如果是这样,没有对计时器的字段引用(只有本地引用)会导致垃圾收集本身......但我认为 DispatcherTimers 不是这种情况......
    • @JeffN825 所有对象都遵循相同的 GC 规则:如果您无法从 GC 根目录访问,那么您就有资格进行 GC。在这种情况下,该代码甚至不是来自正确的计时器类。
    • @dlev 只是没有意识到这是一个 DispatcherTimer - 请参阅我的编辑
    • 我的意思是,只有一个本地引用的本地范围的 Threading.Timer 没有根......因此将被 GC 处理而不会滴答作响。
    • @JeffN825 这并不总是正确的......因为计时器可以直接或间接地“根植”......我没有检查 Threading.Timer 源(通过反射器)可以肯定,但是AFAIK 它在内部调用 TimerBase.AddTimer ,这似乎为本地范围的计时器创建了一个引用......所以它也很可能在你的场景中“间接植根”......
    【解决方案2】:

    当您只是构造一个 DispatcherTimer 时,没有什么可以阻止它被 GCed。但是,您设置了IsEnabled = true,它将在计时器上调用Start()。当这种情况发生时,这行代码将被执行:

    this._dispatcher.AddTimer(this);
    

    现在Dispatcher 本身正在生成计时器,这意味着它不能被 GCed。

    【讨论】:

      【解决方案3】:

      它将被添加到将被植根的Dispatcher 队列中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多