如何防止System.Threading.Timer在UWP中被垃圾收集

本文关键字:UWP System 何防止 Threading Timer | 更新日期: 2023-09-27 18:15:45

我试图在我的应用程序中实现撤销功能。我有这样的代码Timer timer = new Timer(UndoDeleteTimerFinish, email, UndoBannerDisappearTime, Timeout.Infinite);UndoDeleteTimerFinish()将使横幅消失。但是,有时横幅会卡在屏幕上,我发现在这种情况下,UndoDeleteTimerFinish()不会被调用。我认为计时器一定是GC收集的。我想知道如何防止计时器得到GC收集,并在同一时间响应,并允许用户与应用程序交互。

如何防止System.Threading.Timer在UWP中被垃圾收集

计时器有一个对定义UndoDeleteTimerFinish的对象的引用。如果该对象的唯一引用是对Timer的引用,反之亦然,则它们都符合垃圾收集的条件。

快速而肮脏的修复方法是让一个不被垃圾收集的对象保存对Timer的引用。

class ObjectNotGettingGarbageCollected{
     Timer _timer; //won't be GC'd
     SomeMethod(){
           _timer = new Timer(UndoDeleteTimerFinish, email, UndoBannerDisappearTime, Timeout.Infinite)
     }
}

同样,只要状态对象(email在某个地方被引用,CLR就会将计时器保存在其计时器队列中,并且计时器对象不会被垃圾收集。所以我会检查'email'对象的状态是什么,你把它作为状态参数传递给Timer。

更多信息在这里:

System.Threading.Timer构造函数有几个重载;除了一个之外,其他都接受一个状态参数,该参数在计时器触发时传递给TimerCallback委托。

事实证明,这个状态参数(和TimerCallback委托)对垃圾收集有一个有趣的影响:如果它们都没有引用System.Threading.Timer对象,它可能被垃圾收集,导致它停止。这是因为TimerCallback委托和状态参数都被包装到一个GCHandle中。如果它们都没有引用计时器对象,则它可能符合GC的条件,从而将GCHandle从其终结器中释放出来。

单参数构造函数不会遇到这个问题,因为它将this传递给状态(非null)。System.Threading.Timer的大多数实际用法要么引用回调中的计时器,要么使用状态计时器,因此可能不会注意到这种有趣的垃圾收集行为。

http://blog.stephencleary.com/2011/07/systemthreadingtimer-constructor-and.html