Reputation: 305
I normally avoid using local variables to hold references to timers because when the local variable goes out of scope the timer gets garbage collected and stops firing. However, I ran into a bit of code that seems to get around this problem by referencing the timer itself through a closure in a lambda expression that is attached to the Elapsed
event.
{
var bkgTimer = new System.Timers.Timer(timeDelay) {AutoReset = false};
bkgTimer.Elapsed += (sender, args) => Handler(e, bkgTimer);
bkgTimer.Start();
}
Then later, in the Handler:
private void Handler( ... timer)
{
...
timer.Dispose();
}
It appears to work. Are there any problems with this approach? I wondered if it could lead to a memory leak since I don't understand what the lifetime of the lambda closure is controlled by.
Upvotes: 0
Views: 2165
Reputation: 185902
An object cannot avoid GC simply by referencing itself — that's the key distinction between true garbage collectors and reference-counting techniques. If the GC cannot reach it from a root, it will collect it.
Call GCHandle.Alloc
to prevent collection, and call GCHandle.Free
in the Handler
method to prevent leakage.
The advice in the documentation to use GC.KeepAlive
only applies to long-running methods. If the method exits immediately, as yours appears to do, GC.KeepAlive
won't have the desired effect.
Incidentally, you shouldn't need a separate handler method:
var bkgTimer = new System.Timers.Timer(timeDelay) {AutoReset = false};
var timerHandle = GCHandle.Alloc(bkgTimer);
bkgTimer.Elapsed += (sender, args) => {
…
timerHandle.Free();
bkgTimer.Dispose();
};
bkgTimer.Start();
Upvotes: 2