Click here to Skip to main content
15,845,830 members

Comments by Daniel Grunwald (Top 9 by date)

Daniel Grunwald 23-Apr-11 17:19pm View    
This only applies to System.Threading.Timer. The other timers keep themselves alive until explicitly stopped.
Daniel Grunwald 23-Apr-11 17:18pm View    
The reference chain here is actually:
static list of timer callbacks (within .NET runtime) => new System.Threading.TimerCallback(...) => mtd.TimerCall(o){} => mtd => m_timer
If the timer would get garbage collected, it would deregister the callback from the static list. But it can't get garbage collected, since it still is reachable from a GC root. The GC can't look into finalizers to see that they would remove the last remaining reference.

So in a sense, this is a "cycle" that the GC can't deal with - but that's because the GC can't look into the future to see that if it collected an object that is still reachable, it would become unreachable.

But your solution reads as if the GC couldn't deal with cycles of references - that's giving the wrong impression, as the GC can handle those fine. One only needs to be aware that the whole cycle will live as long as the longest-lived object within the cycle.
Daniel Grunwald 23-Apr-11 17:03pm View    
Yes, it depends on the timer implementation. System.Threading.Timer in .NET 4.0 indeed looks like it keeps only the delegate alive, so breaking the reference chain from the delegate to the timer is sufficient to get the timer object collected (which will stop the timer in its finalizer).
However, System.Timers.Timer and System.Windows.Forms.Timer do keep themselves alive, so those need to be stopped explicitly.
Daniel Grunwald 23-Apr-11 12:07pm View    
A System.Threading.Timer starts automatically when the constructor is called.
If you add a "m_timer.Start()" call to your WinForms code, you'll find that the same memory leak will occur.
Daniel Grunwald 23-Apr-11 11:56am View    
The GC can handle circular references just fine, even with events and delegates.
The "event problem" only occurs when you have a long-lived object as events source, and a short-lived object as event handler: the delegate will keep the event handler alive as long as the event source lives.
In the worst case (event source lives forever, e.g. static event), the event handlers will never be garbage collected.
However, if the event source has a short lifetime, you do not need to unregister event handlers.