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

时间:2013-06-02 01:06:27

标签: c# timer lambda garbage-collection

我通常避免使用局部变量来保存对计时器的引用,因为当局部变量超出范围时,计时器会被垃圾收集并停止触发。但是,我遇到了一些似乎通过附加到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闭包的生命周期是由什么控制的。

1 个答案:

答案 0 :(得分:2)

对象无法简单地通过引用自身来避免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();