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