I have written a unit test to comfirm the “Dispose” on my class does unhooks all events and disposes a timer that references the object.
However sometimes WeakReference.IsLive() returns true when I would expect it to return false?
So is there a delay after a full GC before WeakReference.IsLive() is updated?
If not, can you think of anything else that would be giving me unrepeatable results?
WeakReference weekJobWatchDog = new WeakReference(jobWatchDog);
jobWatchDog = null;
// not collected before Dispose called due to timer and events etc
GC.Collect(); GC.Collect();
Assert.IsTrue(weekJobWatchDog.IsAlive);
((IDisposable)weekJobWatchDog.Target).Dispose();
// is now collected as Dispose unlocked all events and dispoed the timer
GC.Collect(); GC.Collect();
Assert.IsFalse(weekJobWatchDog.IsAlive); // sometimes this fails, about 1 in 4 runs
See also Testing Finalizers and IDisposable for a related but different question.
How can I write a unit test to determine whether an object can be garbage collected? has a soltuion that includes calling GC.WaitForPendingFinalizers(), however I rather not call GC.WaitForPendingFinalizers() as I wish to prove that my dispose works and if it worked there will be no need for any finalizers to run.
This was the issue that I had:
When you call Dispose() on a System.Timers.Timer it may return before the Win32 timer has been destroyed. Hence there is still a “root” in unmanaged space keeping the timer alive. The time had an event handler that that kept my object alive.
As this is very timely related, most of the time the Timer would get GCed and so would my object. However sometimes (say 1 in 10 times) the Timer would be kept alive and so would my object.
A short Sleep() would make my test pass 100% of the time, so does unhooking the event on the timer before disposing it, so the timer can’t keep my object alive.
see also How do I safely dispose a System.Timers.Timer?