System.Threading.Timer Constructor and Garbage Collection

This week, we take a break from the option parsing posts to bring you an interesting corner case from the BCL.

The System.Threading.Timer constructor has several overloads; all except one take a state parameter which is passed to the TimerCallback delegate when the timer fires.

It turns out that this state parameter (and the TimerCallback delegate) have an interesting effect on garbage collection: if neither of them reference the System.Threading.Timer object, it may be garbage collected, causing it to stop. This is because both the TimerCallback delegate and the state parameter are wrapped into a GCHandle. If neither of them reference the timer object, it may be eligible for GC, freeing the GCHandle from its finalizer.

The single-parameter constructor does not suffer from this problem, because it passes this for the state (not null). Most real-world usage of System.Threading.Timer either references the timer from the callback or uses the timer for the state, so this interesting garbage collection behavior will probably not be noticed.

This blog post was prompted by my own question on Stack Overflow.