6

I've just stumbled across some code that uses the GC.KeepAlive() method and I am trying to understand how it works. For example, in this code:

Timer timer = new System.Timers.Timer(5000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Enabled = true;
GC.KeepAlive(timer);

In this code, my understanding is that a Timer object is created, which spawns a thread that runs every 5 seconds. Next, the GC line is ran. Then the method exits, destroying the timer when garbage collection runs.

The KeepAlive only keeps it alive prior to the call to KeepAlive, which it looks to me is about 0.0000001 seconds and it won't be destroyed there anyway since there is a local reference to it (unless it's destroying it because nothing else happens to the timer object?)

Either way, by the time the 5000 interval is hit the method will have ended ages ago and it's very likely the timer is destroyed. So what's the purpose of that line?

NibblyPig
  • 51,118
  • 72
  • 200
  • 356
  • 1
    Ask the original developer? – dtb Jun 07 '13 at 17:00
  • As long as you're dealing with managed code (i.e. Entirely in .Net), there's no need to use `GC.KeepAlive`. All it does is keep a reference to the timer object so it won't be garbage collected. [The docs](http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx) say it's really intended for use with objects allocated in managed code that are being passed to unmanaged code (e.g. a Win32 API call). So for this particular example, it seems pointless. – ThatBlairGuy Jun 07 '13 at 17:13
  • 1
    Sadly the original developer is long gone, and has left me this beauty of a project to maintain :) – NibblyPig Jun 07 '13 at 18:17
  • 1
    Just to be clear, having a local doesn't guarantee the object will not be garbage collected during the function. The garbage collector can look ahead to see if the local is referenced anymore during the method and if not it may decide to garbage collect it. The purpose of GC.KeepAlive is to work around this problem and force an object to live *at least* until the GC.KeepAlive call returns. – Micah Zoltu Jan 27 '14 at 19:33

2 Answers2

4

So what's the purpose of that line?

Nothing. You shouldn't be using it as it's not helping anything. That code was probably written by someone not particularly familiar with how the Timer class works.

Internally the Timer class will use entirely different means of ensuring that it is not garbage collected before it should be. See this question for the details.

Community
  • 1
  • 1
Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    Also this: http://stackoverflow.com/questions/4959149/do-timer-object-get-gc-ed-when-no-other-object-references-them – Sam Harwell Jun 07 '13 at 17:11
  • Interesting. I wonder if that's true for System.Timers.Timer (that the OP is using) and System.Threading.Timer. I seem to recall that the threading timer, at least, would get collected. Will have to research that. ... And the answer to my question: http://stackoverflow.com/q/4962172/56778 – Jim Mischel Jun 07 '13 at 18:24
  • 1
    @JimMischel It's pretty easy to test. A few sample programs have indicated that neither the system.timers.timer nor the system.threading.timer will be collected while executing. – Servy Jun 07 '13 at 18:28
1

In this context, there's no reason for that line. The only time it can help is if there is a lot of code between the timer.Enabled and the call to KeepAlive, as in:

    timer.Enabled = true;
    // lots of code here that does
    // things that take some time
    GC.KeepAlive(timer);
}

That will prevent the garbage collector from collecting the timer before the method ends. Without the call to KeepAlive, the GC could decide that timer isn't used any more after Enabled is set, and it could do an early collection.

If you want a persistent timer, you have to declare it at class scope.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • This is contrary to Servy, which I suppose has the better arguments. Mind you, out of a habbit, my timers all are class level, though I might try the local option soon, without KeepAlive, which seems to be useful only for both unmanaged code still having a reference and delaying finalization. – Andreas Reiff Feb 15 '14 at 14:39
  • @AndreasReiff: Servy's answer is correct, as I pointed out in my comment to his question. I also provided a link to a question that provides a very detailed answer to the question. – Jim Mischel Feb 16 '14 at 04:37