0

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

{
    var bkgTimer = new System.Timers.Timer(timeDelay) {AutoReset = false};
    bkgTimer.Elapsed += (sender, args) => Handler(e, bkgTimer);
    bkgTimer.Start();
}

然后,在处理程序中:

private void Handler( ... timer)
{
    ...
    timer.Dispose();
}

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

4

1 回答 1

2

一个对象不能简单地通过引用自身来避免 GC——这是真正的垃圾收集器和引用计数技术之间的关键区别。如果 GC 无法从根访问它,它将收集它。

调用GCHandle.Alloc防止收集,调用方法防止泄漏GCHandle.FreeHandler

文档中使用的建议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();
于 2013-06-02T03:45:29.130 回答