views:

88

answers:

3

In my WPF-application I call new windows in the following way:

_newWin = new WinWorkers_AddWorker();
_newWin.WindowState = this.WindowState;
_newWin.Show();

Where _newWin is a private Window object.

My question is should I assign a null value to _newWin after I call _newWin.Show()?

Will this decrease memory consumption, because garbage collector / destructor will clean a null value objects earlier?

Thanks.

A: 

It won't delete the object because it will be referenced elsewhere in the app (in the internal code) Otherwise, setting the value of _newWin to null and having it garbage collected would make your window disappear (and likely crash your program), which doesn't happen.

Kendrick
+2  A: 

Garbage collection doesn't clear null objects. If you set a reference to null you just remove a reference that was pointing to an object so that you actually lower its retain counter.

But this counter will be decreased also when an object goes out of scope with no way to be reclaimed back by code.. so what you are trying to do is useless.

The GC will choose anyway to release it only when it isn't referenced anymore, but if you show that window you will be sure that somewhere it is referenced anyway..

EDIT: as stated in comment maybe reference counting is not the way the .NET vm does (sorry but I don't use M$ platform) but the principle remains the same. Your window won't be GCed anyway since it is visible.

Jack
Dykam
@Dykam is correct and it's mark and sweep. For that matter, it can be collected before it falls out of scope. Shall add an answer detailing.
Jon Hanna
Mono isn't reference counted either.
Jon Hanna
I don't use C# at all..
Jack
Ah. Yes, your point about scope and reference counts holds for some languages like VB6, PHP and Python. It's not true of .NET or Java.
Jon Hanna
+5  A: 

It's generally irrelevant to set a value to null. It's very rarely useful. It's occasionally harmful.

Let's consider first the simplest case:

private void DoStuff()
{
  var newWin = new WinWorkers_AddWorker();
  newWin.WindowState = this.WindowState;
  newWin.Show();
  int irrelevant = 42;
  this.whoCares = irrelevant * 7;
  int notRelevantEither = irrelevant + 1;
  this.stillDontCare = notRelevantEither * irrelevant;
}

Here newWin only exists in this method; it is created in it and doesn't leave the scope of the method by being returned or assigned to a member with a wider scope.

Ask a lot of people when newWin gets garbage collected, and they'll tell you that it will happen after the line with this.stillDontCare, because that's when newWin goes out of scope. We could therefore have a slight win by assigning newWin = null just after its last use, but its probably negligible.

Conceptually this is true, because we can add code that deals with newWin anywhere up until that point, and newWin is there for us to make use of.

In fact though, it is quite likely that newWin becomes eligible for collection right after .Show(). While it is conceptually in scope after then, it isn't actually used and the compiler knows that. (By "compiler" from now on I'm going to mean the entire process that produces actual running code, combining the IL compiler and the jitter). Since the memory used by newWin itself (that is, the reference on the stack, not the object) is no longer used the compiler could use that memory for irrelevant or something else. There being no live reference any more, the object is eligible for collection.

Indeed, if the last few methods called on an object don't actually use the this pointer (whether directly or by using member fields) then the object can even be collected before those methods are called, because they don't actually make use of the object. If you had a method whose this pointer was never used (again, directly or indirectly) then it might never actually be created!

Now, bearing this in mind, we can see that it really isn't going to make even that slight negligible difference that it would seem to make, if we were to assign null to the variable before the variable falls out of scope.

Indeed, it is just about possible that the assignment could even make it take longer to become eligible, because if the compiler couldn't see that that use of the variable was not going to affect the object (unlikely, but perhaps it could happen if there are try...catch...finally blocks making the analysis more complicated), then it could even delay the point at which the object is deemed eligible. It is again probably negligible, but it is there.

So far so simple; good stuff happens if we leave well alone, and leaving well alone is easy.

It is however possible for a reference to benefit from being set to null. Consider:

public class SomeClass
{
  private WorkerThing _newWin;
  private void DoStuff()
  {
    _newWin = new WinWorkers_AddWorker();
    _newWin.WindowState = this.WindowState;
    _newWin.Show();
  }
}

Consider here, that this time after DoStuff() is called, _newWin is stored in a member variable. It will not fall out of scope until the instance of SomeClass falls out of scope. When will that happen?

Well, I can't answer that question, but sometimes the answer is important. If the SomeClass itself is also short-lived, then who cares. It'll fall out of scope soon enough, taking _newWin with it. If however, we assigned _newWin = null then the object would immediately be eligible for collection.

Now, some important caveats to this:

  1. In the first place, there is no good reason for _newWin to be a member variable. If the example above were complete code we would move it back to being local to DoStuff() and gain not only in this efficiency manner, but much, much more importantly in our chances of correctness, as we can't do something stupid to _newWin from another member.
  2. If we are holding onto something in a member variable, it's probably for a good reason. That good reason is going to override being fanatic about cleaning out variables as fast as possible.
  3. Most objects just don't take up that much memory by themselves anyway. A member variable here or there isn't going to hurt.

Because of this, the main reason to assign null to a member variable, is simply because null has become the most appropriate value. Assigning null to a member that is no longer going to be used is generally not to release its memory ASAP but because it is no longer appropriate to use, and that becomes impossible - and clearly signalled to the rest of your code as such - when it is null.

If a reference was longer-lived than a method (and hence put in a member variable) and considerably shorter-lived than the containing object and consumed a very large amount of memory, then it's just about possible that assigning null would begin to make sense. In the extremely rare cases where that combination happens, we probably want to assign it to null to indicate that it is no longer there for the class to use anyway, so we're still not going to assign null with the purpose of releasing it to the GC. It's just about possible, but really "nah".

Jon Hanna