Search code examples
c#garbage-collectionfinalizer

Does GC.SuppressFinalize keep an object rooted


In the reference source for Task.Delay() in .NET, I came across a snippet of code:

// ... and create our timer and make sure that it stays rooted.
if (millisecondsDelay != Timeout.Infinite) // no need to create the timer if it's an infinite timeout
{
    promise.Timer = new Timer(state => ((DelayPromise)state).Complete(), promise, millisecondsDelay, Timeout.Infinite);
    promise.Timer.KeepRootedWhileScheduled();
}

The method KeepRootedWhileScheduled is implemented thusly:

GC.SuppressFinalize(m_timer);

What is the purpose of calling GC.SuppressFinalize? Does it really root the object for the garbage collector, is the comment incorrect, or is there something else that I'm misunderstanding?


Solution

  • Keeping a System.Threading.Timer rooted is certainly very important, it stops ticking when you don't. But no, this method has a very misleading name. It probably did something very different in an early version, then it was discovered later that whatever hokey-pokey it did wasn't necessary. It shouldn't, the task keeps a reference on it. This is conjecture without having access to that early source code of course.

    What remains is a micro-optimization, nothing unusual in .NET Framework code. Presumably the timer always gets disposed, no matter what happens, so there's no need for its finalizer. Sounds about right, you'd have to think of a scenario where the task suffers an exception while it is executing Delay(). Well, that doesn't happen. Fairly sloppy editing btw, that's not common in framework code.