如果没有保存引用,SystemTimers.Timer 何时被视为垃圾?

Posted

技术标签:

【中文标题】如果没有保存引用,SystemTimers.Timer 何时被视为垃圾?【英文标题】:When is SystemTimers.Timer considered garbageif no reference is saved? 【发布时间】:2020-06-12 11:05:48 【问题描述】:

我很想知道 System.Timers.Timer 何时被视为垃圾并因此被垃圾收集器收集,如果我不存储对它的引用,但它已启用。 但是在什么时候我的计时器被认为是垃圾?

考虑以下代码:

public void TriggerUpdateStatus() 
    toolStripStatusLabel1.Text = "*";
    new Timer() 
        Interval = 1000,
        Enabled = true
    .Elapsed += new ElapsedEventHandler(
        (object sender, ElapsedEventArgs args) => 
            toolStripStatusLabel1.Text = "";
            Timer t = ((System.Timers.Timer) sender);
            t.Stop();
            t.Dispose();//Is this needed?
        );

当我的代码触发更新时,此代码块将每两秒运行一次,然后在我的表单的底角添加一个星号,表示连接有效且良好。我创建了一个没有引用的计时器,它会在一秒钟后再次移除星星,自行停止并自行处理。

【问题讨论】:

它在运行时如何/为什么会被视为垃圾??? 在第 10 行,它会自行停止,并在第 11 行自行处理。 您问:如果我不存储对它的引用,但它已启用。现在是哪个? 您的 Timer 对象甚至在方法返回之前(根据您的代码)就有资格进行垃圾回收。但是,您无法确切知道何时收集此对象。 .NET 中的 GC 以这种方式是不确定的。请注意,Timer 是一个 Component,它有一个终结器,如果它将在收集时运行(更准确地说,处理终结器队列的时间),它将自动禁用正在运行的计时器。 【参考方案1】:

不,t.Dispose(),没有必要,无论如何都会被收集。

这个问题本身似乎传达了一个关于 GC 和 Dispose 如何工作的深刻误解(我强调了这个词 似乎)。 GC 完全不知道Dispose 做了什么,也不在乎。一个对象是否被处理并不会影响该特定对象是否适合收集;这是两个完全正交的概念。

Dispose 是一种释放非托管资源的机制,它与垃圾收集器的工作方式无关。

如果这很清楚,那么Dispose 尽管有礼貌,但甚至不是绝对必要的; Dispose(或其所需部分)将在最终收集计时器时运行(该对象无法访问且寿命短,因此不应花费太长时间),放入终结器队列并在某个未确定的未来完成;有礼貌并建议 dispose 以便确定性地释放与对象关联的所有非托管资源,而不是依赖于终结器队列决定运行时,这带来了下一点:

为什么你每两秒更新一个Timer 然后立即处理它?拥有一个计时器并每次都重置它不是更容易吗?

【讨论】:

所以如果我没看错你说的话,一旦计时器停止,它就会被收集,或者我可以遇到在计时器停止之前收集它的时间吗?为了回答您的问题,我知道这是解决问题的一种令人发指的方法,我尝试了一些方法,但总是遇到两个计时器不同步或一个计时器完全停止工作的问题。

以上是关于如果没有保存引用,SystemTimers.Timer 何时被视为垃圾?的主要内容,如果未能解决你的问题,请参考以下文章

如果保存了引用的对象,应该更新引用的对象吗?

c#传递引用对象作为参数的时候就没有必要用ref关键字,对吗

保存对其他集合的引用

如何在 iPhone 上保存对特定照片的引用以便在没有选择器的情况下加载?

Doctrine2 ManyToMany 自引用

Firebase 引用对象不会保存到 SwiftUI 中的变量