14

The documentation on PowerShell here has the following interesting comment in it:

PowerShell powershell = PowerShell.Create();

using (powershell)
{
    //...
}

// Even after disposing of the PowerShell object, we still 
// need to set the powershell variable to null so that the 
// garbage collector can clean it up.
powershell = null;

Why does powershell need to be set to null after being disposed?

noonand
  • 2,763
  • 4
  • 26
  • 51
  • 2
    That's a C# question, not a PowerShell question. – Ansgar Wiechers May 15 '13 at 13:46
  • 1
    @AnsgarWiechers - You're correct; upon examining the link, though, it's an odd pattern. Can anyone tell why they didn't go with `using(PowerShell powershell = PowerShell.Create()) {`? Style preference? – Justin Morgan - On strike May 15 '13 at 15:41
  • 8
    For the record that's a generally poor practice and simply is not needed at all in this context. It's unlikely to make any difference at all, and if it would, it would be minuscule. The variable really should have just been created inside the `using`, but even without doing that, there isn't really any justification for nulling it. The remainder of the method will complete *very* quickly, and the powershell object will not consume a significant number of resources once disposed. – Servy May 15 '13 at 16:36
  • 3
    That comment is just plain nonsense. – Brian Rasmussen May 15 '13 at 18:01

3 Answers3

17

It's not directly a PowerShell issue. When a using block terminates, the specified object(s) have their Dispose() methods called. These typically do some cleanup operations, often to avoid leaking memory and so forth. However, Dispose() doesn't delete the object. If a reference to it still exists outside the using block (as in this example), then the object itself is still in scope. It can't be garbage-collected because there's still a reference to it, so it's still taking up memory.

What they're doing in your example is dropping that reference. When powershell is set to null, the PowerShell object it was pointing to is orphaned, since there are no other variables referring to it. Once the garbage collector figures that out, it can free up the memory. This would happen at the end of the method anyway (because powershell would go out of scope), but this way you get the system resources back a little sooner.

(Edit: As Brian Rasmussen points out, the .NET runtime is extremely clever about garbage collection. Once it reaches the last reference to powershell in your code, the runtime should detect that you don't need it anymore and release it for garbage collection. So the powershell = null; line isn't actually doing anything.)

By the way, this pattern looks very strange to me. The usual approach is something like this:

using (PowerShell powershell = PowerShell.Create())
{
   //...
}

This way, powershell goes out of scope at the end of the using block, right after it's disposed. It's easier to tell where the variable is relevant, and you save some code because you don't need the powershell = null line anymore. I'd even say this is better coding practice, because powershell never exists in an already-disposed state. If someone modifies your original code and tries to use powershell outside the using block, whatever happens will probably be bad.

Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
  • 6
    The .NET runtime does not require you to null references and it detects objects that are eligible for collection as soon as they are no longer referenced (i.e. this typically happens before the end of the method). – Brian Rasmussen May 15 '13 at 17:39
  • @Justin Morgan Re the pattern looking strange, well it'd be consistent with the rest of the quality of the code sample then I guess ;-) – noonand May 16 '13 at 11:07
  • @BrianRasmussen Excellent point! Which means it's even less useful to do this. – Justin Morgan - On strike May 16 '13 at 15:28
  • _"If a reference to it still exists outside the using block (as in this example), then the object itself is still in scope"_ -- actually, it's "worse" than that. Even if the variable had been declared as part of the `using` block, the variable lifetime is for the duration of the method call. Inside or outside of a local scope within a method makes no difference. Of course, on the flip side is the fact that in optimized builds, the GC is allowed to discard objects that are still referenced, if it can prove that the reference is never used. – Peter Duniho Jan 06 '18 at 00:13
6

It doesn't need to be set to null, and it really shouldn't be. The .NET garbage collector is quite capable of detecting that an object not being used after a particular instruction even if your code does not assign a null value to the corresponding variable. (See http://blogs.msdn.com/b/cbrumme/archive/2003/04/19/51365.aspx for details.) As for why an "official" example contains this extra code with misleading comments, even docs can have bugs...

Nicole Calinoiu
  • 20,843
  • 2
  • 44
  • 49
1

The advice is incorrect, as long as its unreachable it is eligible for garbage collection. (see What is the correct way to free memory in C# for some code demonstrating this) the only reasons to null things out are

  • To make it easier to troubleshoot memory leaks
  • To remove references (e.g. public properties) that the GC may have trouble determining are unreachable

Both of which you would really only do within an objects Dispose method

Community
  • 1
  • 1
Yaur
  • 7,333
  • 1
  • 25
  • 36