Lambda闭包生命周期和计时器处理程序

本文关键字:计时器 处理 程序 周期 闭包 生命 Lambda | 更新日期: 2023-09-27 18:16:30

我通常避免使用局部变量来保存对计时器的引用,因为当局部变量超出作用域时,计时器会被垃圾收集并停止触发。但是,我遇到了一些代码,似乎通过附加到Elapsed事件的lambda表达式中的闭包引用计时器本身来解决这个问题。

{
    var bkgTimer = new System.Timers.Timer(timeDelay) {AutoReset = false};
    bkgTimer.Elapsed += (sender, args) => Handler(e, bkgTimer);
    bkgTimer.Start();
}
然后,在Handler中:
private void Handler( ... timer)
{
    ...
    timer.Dispose();
}

它似乎有效。这种方法有什么问题吗?我想知道它是否会导致内存泄漏,因为我不明白lambda闭包的生命周期是由。

Lambda闭包生命周期和计时器处理程序

控制的。

对象不能仅仅通过引用自身来避免GC—这是真正的垃圾收集器和引用计数技术之间的关键区别。如果GC不能从根到达它,它将收集它。

调用GCHandle.Alloc防止收集,调用Handler方法中的GCHandle.Free防止泄漏。

文档中使用GC.KeepAlive的建议只适用于长时间运行的方法。如果该方法立即退出,就像您的方法那样,那么GC.KeepAlive将无法达到预期的效果。

顺便说一下,你不需要一个单独的处理程序方法:
var bkgTimer = new System.Timers.Timer(timeDelay) {AutoReset = false};
var timerHandle = GCHandle.Alloc(bkgTimer);
bkgTimer.Elapsed += (sender, args) => {
    …
    timerHandle.Free();
    bkgTimer.Dispose();
};
bkgTimer.Start();