0

I recently learned how to use Microsoft.VisualBasic.FileIO.TextFieldParser to parse a text input. In the example given to me, the TextFieldParser is called using the keyword using

using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(new StringReader(str)))

Though after some further researches, I notice that the practice of using using keyword for TextFieldParser is not universal.

As far as I understand, .Net Framework has both managed and unmanaged resource. And when we use unmanaged resource, we should worry about memory leak and thus we should take care of the disposal of the unmanaged resource we use. One best way to do this is by putting them on using context.

All these drive me to have two questions in my mind, one particular and one general. Here are my questions:

  1. The particular: Is TextFieldParser actually managed or unmanaged?
  2. The general: Is there a definite way for us to know if a resource is managed or unmanaged(such as looking at X thing in the class, or such alike, or even check something from MSDN - if any should be checked - will do). I was told some guidance along my short programming experience such as that (i) most of the .Net classes are managed, (ii) System.Drawing classes have some unmanaged resources, (iii) beware of all database, network, and COM classes because they are typically unmanaged, etc... and the list goes on which I keep adding till now. But I wonder if there is any definite way to know this?

I would really appreciate if the more experienced could help to further guide me on this issue.

Community
  • 1
  • 1
Ian
  • 30,182
  • 19
  • 69
  • 107

2 Answers2

3

You're missing the point. Whenever any class implements IDisposable, you should call Dispose when you're done with it.

Whether the class uses unmanaged resources or not is internal to the class, you shouldn't care about it at all. Every class that uses unmanaged resources should also have a finalizer that clears up those unmanaged resources if you didn't dispose of the class explicitly. Dispose just allows you to clean its resources (both managed and unmanaged, though this doesn't necessarily mean freeing up the memory immediately) in a more deterministic and immediate fashion. For example, Disposeing a FileStream will release the file handle immediately, while if you don't Dispose (or Close), the file will be opened until the next collection and finalization.

EDIT:

To show that Dispose may also be necessary to clean up managed resources, we only have to look at event handlers. In particular, the case when you're subscribing on an event of a class that has a longer lifetime than you do:

var control = new MyHelperControl();
MyParentForm.Click += control.DoSomething();

Now, even if control goes out of scope, it will survive as long as MyParentForm - it's still referenced by the event handler. The same problem grows to absurd proportions when the parent has the same lifetime as the whole application - that's can be a huge memory leak. An example would be registering event handlers on the main form of an application, or on a static event.

There might also be other things that happen in the Dispose. For example, again with Windows forms, when you call Dispose on a Control, a whole lot of things happen:

  • All the unmanaged resources are released. Since Winforms controls are wrappers of the native controls to an extent, this is usually a lot of resources - the control itself, any pens, brushes, images... all of those are native resources. They will also be released if you forget a Dispose, since they all have finalizers, but it might take more time - which is especially painful when you create and destroy a lot of those objects. For example, there's a limited supply of GDI+ object handles, and if you run out, you get OutOfMemoryException and you're out.
  • Dispose of all sub-controls.
  • Remove any context menu handlers (remember, context menu is a separate component that's only linked to another control).
  • Remove any data bindings.
  • Remove itself from the parent container, if any.
  • If the control is a window with its own message loop, kill the message loop.

The funny part is that the unmanaged resources matter the least, really - they always have a finalizer. The managed resources are trickier, because you're more or less forbidden to handle managed references in a finalizer (because they might have already been released, or they might be in the middle of being released, or they might start being released in the middle of your finalizer... it's complicated). So doing MyParentForm.Click -= this.OnClick; is not a good thing to have in your finalizer - not to mention that it would require you to make every such class finalizable, which isn't exactly free, especially when you expect the finalizer to actually run (when you do a Dispose, the GC is alerted that this instance no longer needs a finalization).

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • Do you mind to further elaborate what you explain? Does that mean that any class with `IDisposable` is unmanaged and any class without `IDisposable` managed? – Ian Jan 05 '16 at 10:04
  • @Ian No, I mean that it's irrelevant whether a class holds an unmanaged resource or not. Unless the class is very poorly written, it will release its unmanaged resources eventually even if you don't call the `Dispose` method. On the other hand, a `Dispose` method might be outright *required* for managed resources as well - the typical example being memory leaks through event handlers. – Luaan Jan 05 '16 at 10:07
  • @Ian: Most classes that implement `IDisposable` will not directly own an unmanaged resource. However, they will often own another class implementing `IDisposable`. Going down this chain will most of the time end in an unmanaged resource. An example: `YourClass` has a `FileStream` field. The `FileStream` class has `SafeFileHandle` field. The `SafeFileHandle` owns the underlying OS unmanaged file handle. Disposing `YourClass` should dispose `FileStream` which diposes `SafeFileHandle` which will release the unmanaged file handle. – Martin Liversage Jan 05 '16 at 10:11
  • @Ian And looking at the source for `TextFieldParser` in particular, it does really fit this - the `Dispose` method disposes of other `IDisposable`s owned by the class. And while it has a finalizer, it doesn't actually directly have any unmanaged resources - presumably, it's there for extension reasons (the virtual `Dispose` method kind of requires it). So calling `Dispose` means that the text stream is closed earlier, and you avoid the overhead of having a finalizable class. But not using `Dispose` is not going to *leak* anything - just delay some clean up. – Luaan Jan 05 '16 at 10:12
  • I am trying to understand what you are saying here: are you saying that: (1) we cannot know if a class uses `unmanaged` class or not, but as long as it implements `IDisposable` we can free its resources more deterministically (2) Even if a resource is `managed`, it doesn't mean that it will not cause memory leak if `Dispose` is not called correctly. Thus implementation of `IDisposable` is just the way a good programmer would do to its class if he/she knows that his/her class takes up some big amount of resources. Do I understand correctly? – Ian Jan 05 '16 at 10:13
  • @Ian (1) Yes. But the more important point is that you don't really *care* - any class that holds an unamanaged resource should also have a finalizer. Just because the resource is unmanaged doesn't mean that a managed object is free to let it rot unreleased. (2) It's not really about a big amount of resources - that really is mostly irrelevant. It has more to do with lifetime - again, event handlers are a great example. I'll update the answer with a full example. – Luaan Jan 05 '16 at 10:16
  • Thanks for the trouble. Really appreciate what you have done. I am looking forward for your updated answer. – Ian Jan 05 '16 at 10:17
  • @Ian Updated now. Hopefully, it will show why it's a good idea to *always* `Dispose` of anything that implements `IDisposable` :) – Luaan Jan 05 '16 at 10:30
  • @Luaan that is a detailed explanation, more than what I expected. Thanks for the effort! As I might already have wrong concept in my mind. It may take more time to digest your answer fully. But you are saying that both managed and unmanaged are actually will be finalized pretty nicely by GC. And the cause of the memory leak is not because any type (managed or unmanaged) is not disposed but because either they are not disposed **on time** or we forgot that it is still referenced somewhere. The disposable/non-disposable and managed/unmanaged as well as leak/not-leak are really different issues. – Ian Jan 05 '16 at 10:38
  • @Luaan and not only so, regardless of whether a class is using managed or unmanaged resources, we do not really care. But the `IDisposable` is couple of `using`, in which most of the time `IDispoable` is implemented to free some resources (managed/unmanaged) deterministically. Do I understand correctly? – Ian Jan 05 '16 at 10:44
  • @Ian Yeah, as far as the GC is concerned, there is no memory leak - as you can easily see, the reference is still there, in that event handler delegate. Of course, if the class is poorly written, it might very well leak unmanaged resources as well (say, it might omit the finalizer entirely or have a bug) - there isn't really a way to *force* the implementers to release their unmanaged resources properly, and no way to do it automatically - hence why those resources are called "unmanaged". However, you only need unmanaged resources *very* rarely - you usually use (or write) managed wrappers. – Luaan Jan 05 '16 at 10:45
  • @Ian Yeah, `using` is a nice little bit of syntax sugar that makes it trivial to call `Dispose` properly - it's basically the equivalent of `var myClass = new MyClass(); try { ... } finally { myClass.Dispose(); }`. It makes disposal very easy even in error conditions. – Luaan Jan 05 '16 at 10:46
  • @Luaan I *kind of* getting it. Really thanks! I will learn more of it by myself based on your guidance. I appreciate your time, effort, and nice explanation! =) – Ian Jan 05 '16 at 10:48
1

The use of any classes implment IDisposable interface should be either wrapped in using (...) {} or be disposed nicely where appropriate.

Gang Gao
  • 1,051
  • 8
  • 9