4

While looking at the Timer documentation I ran across the following example with this comment:

    // Normally, the timer is declared at the class level,
    // so that it stays in scope as long as it is needed.
    // If the timer is declared in a long-running method,  
    // KeepAlive must be used to prevent the JIT compiler 
    // from allowing aggressive garbage collection to occur 
    // before the method ends. You can experiment with this
    // by commenting out the class-level declaration and 
    // uncommenting the declaration below; then uncomment
    // the GC.KeepAlive(aTimer) at the end of the method.
    //System.Timers.Timer aTimer;
    code in between
    // If the timer is declared in a long-running method, use
    // KeepAlive to prevent garbage collection from occurring
    // before the method ends.
    //GC.KeepAlive(aTimer);

Does this mean that the GC in C# is allowed to garbage collect local variables even if it would have side effects? Presumably because I'm not accessing the timer afterwards again the GC can collect it earlier?

Not sure I'm a fan of such an optimization if I understand this correctly (but then I probably don't ;) )

Björn Lindqvist
  • 19,221
  • 20
  • 87
  • 122
Voo
  • 29,040
  • 11
  • 82
  • 156
  • 2
    Objects are eligible for collection when the GC determines that [nothing outside a finalizer would notice the object's destruction](http://blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx). – Raymond Chen Dec 07 '11 at 02:40
  • possible duplicate of [Do Timer object get GC-ed when no other object references them?](http://stackoverflow.com/questions/4959149/do-timer-object-get-gc-ed-when-no-other-object-references-them) – Hans Passant Dec 07 '11 at 04:51
  • @Raymond Thanks, sadly one can't mark a comment as the correct answer :-) – Voo Dec 07 '11 at 14:29

2 Answers2

2

Yes, GC might collect local variable before ending of the scope, as soon as after last use of the variable. Putting GC.KeepAlive at the end of the method ensures that the variable will be 'alive' until the KeepAlive call.

C# is imperative language so the GC hasn't been designed to know anything about side effects.

tia
  • 9,518
  • 1
  • 30
  • 44
  • Are you sure you're answering the question? – user541686 Dec 07 '11 at 01:57
  • @Mehrdad: Tia did answer it; just in a much more brief manner than I did. – Daniel Mallott Dec 07 '11 at 02:02
  • @DanielMallott: I don't understand why the *object* remaining alive has anything to do with a garbage collection getting triggered... the comment says that this prevents the GC from being 'aggressive', while this answer merely says that the object is not collected. – user541686 Dec 07 '11 at 03:20
  • @Mehrdad: the GC is naturally aggressive. The trick to it is to keep the object in scope - in this case by calling it at the end of the method. Otherwise, the GC will (potentially) collect an object as soon as it deems to have taken it out of scope. The specific case in the original question is simply a case of Microsoft telling you how to game the GC. – Daniel Mallott Dec 07 '11 at 03:31
  • @DanielMallott: Keeping the object alive doesn't mean the GC will be less aggressive, though -- it just means it won't collect the object when it runs. – user541686 Dec 07 '11 at 03:37
  • Sweet and short but that's the easiest way to make sure to get nothing wrong ;-) Seems like the differences between the .NET GC and Hotspot may be more interesting than I thought, good idea to read the spec a bit. – Voo Dec 07 '11 at 14:27
1

As far as I understand the GC, it will mark any variable or object that it believes is no longer needed as a candidate for Garbage Collection during the next GC cycle. I'm not certain I understand the particular application here, but I do know there are cases where the GC might mark a resource for collection when it is still needed (but does not appear so due to the way the code is written).

Normally, during methods, an object or variable stays in scope for the duration of the method call, but if the method call lasts longer than the time between GC cycles, the GC might see your Timer object as out of scope and mark it for collection. Adding the GC.KeepAlive method forces the GC to wait until the method exits before acting on the Timer object.

Daniel Mallott
  • 298
  • 5
  • 7
  • 1
    The object is still in scope as long as the method hasn't returned even if 100 GC cycles run, so that's not it. It seems that the GC is allowed to make a liveness analysis and ignore "dead" variables for its root set (maybe the GC does work on the JITed code and not the bytecode representation in which case this is a simple side effect of the usual optimizations - would make for a good explanation for specifying it this way) – Voo Dec 07 '11 at 14:15