views:

190

answers:

7

Suppose there is the following code:

foreach (...)
{
    List<int> localList = new List<int>(100);

    // do stuff

    localList = null;
}

From time to time, I am tempted to null references just as the procedure is about to exit (that is, return) or in this case, just as it is about to loop. Is there any benefit to doing so, even if a small one?

+4  A: 

No. In fact, "nulling" local variables can, under some circumstances, prevent garbage collection. In normal operation, as soon as a variable is no longer reachable from any executing code, it becomes available for garbage collection. If, at the end of your method, you "null-out" the variable, you keep it "alive" until that moment, and actually delay it's availability for garbage collection.

Mark
Are you sure of that, or is that only because the optimizer drops statements like "x = null" that are the last usage in a given scope for a variable?
Mark
@Dean J, the variables lifetime for the purpose of a GC is often much shorter than it's enclosing scope. It's lifetime ends immediately after it is no longer used within the method. Scope's are C# construct which has no real meaning for a GC operation.
JaredPar
@Adam: I'm paraphrasing Jon Skeet in this answer, from something I read long long ago. Having done some more looking, he's revised his statements for 1.1, saying he thinks that the 1.1 runtime is smarter than the 1.0 runtime in this respect. Certainly the implication is, as JaredPar states, that the lifetime can be shorter than the enclosing scope.
Mark
@Dean J, see the blog article I referenced. Local lifetime is not connected to scope but instead is connected to use. Scope just happens to limit use effectively creating a max lifetime. Locals can be collected long before their declaring scope is exited.
JaredPar
Most of the time, it suffices that *conceptually* they last until they fall out of scope, because up until then you can add a line to the program that uses them and of course the compiled code will change so that they last long enough. It's only in rare cases that the reality that they can be collected long before then has practical impact.
Jon Hanna
@Jon Hanna: the question wasn't about conceptually... it was about reality. In most cases it's fine to have a simplistic understanding of a system, but then there's that one time where you get bitten for it. Better to have a complex understanding of the system, especially if you're going to have to work with it all the time.
Mark
Agreed. But the concept of scope does have some impact, so one needs to understand why debuggers may differ from release, viz. that some debug settings will make it work to scope rather than before. Without noting both, one gets "but it works in the debugger!" bugs.
Jon Hanna
+2  A: 

Not if the declaration is within blocks like you have. Once it's out of scope the reference will be nullified automatically and GC'd.

Pat
Ok, so if I exit, you are saying there is no benefit because it will go out of scope. However, if I loop, it remains in scope, even though I no longer need it. It is garbage to me and I want a new instance. Perhaps if I null it the memory will be freed sooner?
broiyan
It could be, but there is no guarantee, as it's left up to the GC. If you're running into memory issues, definitely try a memory profiler (ANTS profiler for example) as nullifying in a method is probably not gonna be your silver bullet.
Pat
+1  A: 

No. Let the GC do its job and only help it if you need to.

Kent Boogaart
+11  A: 

There is no benefit to doing this for local variables. The CLR knows, by means of the JIT, exactly when a local variable is no longer used within a method and hence collectable.

Raymond Chen recently did a very in depth blog article on exactly when objects are collectible . It covers this scenario in detail and is worth the read

There is however a couple of exceptions to this rule. If the local variable in question is captured into a closure or an iterator then yes nulling out the variable has an effect. Namely because the local is no longer a local but instead is a field and has different GC semantics.

JaredPar
+1: That was a great blog article.
Dan Tao
+2  A: 

I wrote a long and exhaustive blog article answering this question.

To summarize, the general answer is "no; there is no benefit". However, there are a few special cases:

  • Static fields should be set to null when they are no longer needed - unless the process is shutting down, in which case setting static fields to null is unnecessary.
  • Local variables hardly ever need to be set to null. There is only one exception: It may be beneficial to set local variables to null if running on a non-Microsoft CLR.
  • Instance fields hardly ever need to be set to null. There is only one exception: An instance field may be set to null if the referencing object is expected to outlive the referenced object. [Note that the semi-common practice of setting instance fields to null in IDisposable.Dispose does not meet this test, and should not be encouraged].

In conclusion: generally speaking, setting variables to null to help the garbage collector is not recommended. If it is deemed necessary, then an unusual condition exists and it should be carefully documented in the code.

Stephen Cleary
I recently came across an exception to not nulling in disposable. A class which "loaded" itself, based on a webresponse, but which was also cacheable. Dispose() ensured that it cleaned up the webresponse and stream, but afterwards it may be used again (semantically immutable) but may not or not for some time (so Dispose() was still necessary). Hence it may be disposed early in its real lifetime, due to the caching.
Jon Hanna
@Jon: Yes, I can see where that would be an exception. That's a very unusual class, though (allowing regular usage after `Dispose`).
Stephen Cleary
@Stephen. Yes, it was purely because to an external view it was "short-lived" but really it was long-lived. In masquerading as something other than what it really is, it aquired some of the characteristics of both. That said, I did still manage to refactor away the nulling (and some other kruft) since writing the above :)
Jon Hanna
+2  A: 

If a class has a finalizer, any non-null object-reference fields will cause the referred-to objects to be held longer than they otherwise would. If the objects are known to be unnecessary even before the finalizer runs, clearing out the object-reference fields will allow the objects to be collected one "generation" sooner than they otherwise would be. That can be a big win.

If the lifetime (useful or not) of an object is expected to outlive the useful lifetime of an object to which it has a reference, needlessly holding a reference will prevent the latter object from being collected until the former is (i.e. the reference will force the latter object to be kept even after it has become useless). Clearing the reference will avoid that problem.

If a class written in vb.net has any "WithEvents variables", they should be cleared out (set them to nothing) any time the object holding them becomes useless. A class cannot be garbage-collected while it holds a reference to a live object in a "WithEvents variable". If e.g. an enumerator holds a "WithEvents" reference to an underlying collection (e.g. so it can receive events if/when the collection is changed) and its Dispose handler does not clear its reference to the underlying collection, the enumerator will be kept alive as long as the underlying collection is. If the collection is enumerated very many times, this could be a massive memory leak.

supercat
A: 

There is one important case where nulling has an effect, which is when you are using a debug build with some jit optimisations turned off. A lot of the funkier behaviour as to when objects are cleaned up can stop, to make debugging easier.

It's important, because it can lead to a false view of what is happening in the release build.

Jon Hanna