0

I see a lot of example code that wraps FileStream use in a using block or calls Dispose() explicitly.

Do I actually need to do this?

In my (possibly simplistic) understanding, C# is a garbage-collected language and when an object goes out of scope, it is flagged for collection. I assume that the garbage collector is smart enough to call Dispose for me on any object that is IDisposable. Is that true?

Furthermore, I understand that GC in C# is non-deterministic and does not happen directly in response to objects going out of scope, for performance reasons. So, if I am opening a million files per second and not Disposing them, I may be creating a lot of file handles. Is this actually a problem?

I could imagine that the garbage collector in C# is fancy enough to GC in response to a program that gobbles system resources like file handles. Even if it didn't, I could imagine that open file handles are basically free in a modern server OS.

So is calling Dispose being pedantic?

The_Black_Smurf
  • 5,178
  • 14
  • 52
  • 78
John Shedletsky
  • 7,110
  • 12
  • 38
  • 63
  • The garbage collector is non-deterministic. There's no way to know how long it will take to collect the object. In the meantime, it's taking up resources. But since you _know_ when you're done with it, you can Dispose. – John Saunders Jan 08 '15 at 01:46
  • Thanks John. I pointed that out, and that is not my question. – John Shedletsky Jan 08 '15 at 01:56
  • 2
    I have seen an app in production fail because it was not disposing SmtpClient instances, and ran out of some underlying resource it uses. It took months before the conditions were right for that to happen. If a class implements IDisposable, its instances should be disposed explicitly. – hatchet - done with SOverflow Jan 08 '15 at 02:03
  • @hatchet: specifically with `SmtpClient`, I've also seen it not actually send messages until it is disposed. There was a situation where the SMTP server was failing, and we only found out about 2 minutes after we tried to send the message, because that's how long it took for the instance to be garbage collected. – John Saunders Jan 08 '15 at 02:17

2 Answers2

4

I think that the dozens or hundreds of existing questions regarding IDisposable do a decent job of covering this question. That said, addressing your specific ones:

  1. "I assume that the garbage collector is smart enough to call Dispose for me on any object that is IDisposable. Is that true?"

Yes and no. Objects which implement IDisposable usually also implement a finalizer. It's that which causes the GC to dispose the object prior to being collected.

Note that there is significant overhead in dealing with the finalizer, overhead which is suppressed if you dispose an object explicitly. That alone is reason enough to justify making sure you dispose objects correctly.

  1. "I may be creating a lot of file handles. Is this actually a problem?"

Yes, this is actually a problem. Windows has a lot more handle table space now than it used to, but it's still a constrained resource.

Furthermore, the file is still open until the handle is closed. This could prevent other processes from accessing the file when they need to, or could allow the file to be accessed before it's been flushed and so is incompletely written.

  1. "So is calling Dispose being pedantic?"

No. Calling Dispose() on objects (which you own and know no longer need to be used) implementing IDisposable is an important part of any correct program.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Really nice explanation ! I think point 2 is missed in a lot of explanations of the IDisposable problems! – mybirthname Jan 08 '15 at 02:09
  • Please clarify that it's not just objects which implement `IDisposable`, it's "objects which _you create_ which implement IDisposable", or more accurately, "objects for which you are responsible". – John Saunders Jan 08 '15 at 02:18
  • @JohnSaunders: I didn't really intend to enumerate the whole "when to dispose" discussion here, and I think the answer is fine without it, but I've added the comment anyway. :) – Peter Duniho Jan 08 '15 at 02:24
  • Thanks Peter, that really nailed it down for me. – John Shedletsky Jan 08 '15 at 23:04
-3

If I recall correctly, a using block just allocates an object for the lifetime of whatever is inside the braces. This requires the object being created to implement IDisposable, which was intended to release unmanaged resources.

If you use managed resources, it should (eventually) be cleaned up by the GC and it's your call as to whether to use it or not, but it provides a nice syntactic sugar to deal with unmanaged resources by means of a common interface.

Kyle Baran
  • 1,793
  • 2
  • 15
  • 30
  • 2
    Your recollection of `using` is incorrect. `using` by itself allocates nothing; it is a language shortcut for writing a `try`/`finally` block to ensure the object's `Dispose()` method is called. – Peter Duniho Jan 08 '15 at 01:56