Question

Would the garbage collector automatically free the unmanaged resources (whatever, actually) associated with some IDisposable instance if, for example, I forgot to write using statement?

Obviously, I don't know when this would happen, but is it fine to leave the IDisposable to the GC when I don't care about those resources and I'm fine with that they will be disposed eventually?

Was it helpful?

Solution

Would the garbage collector automatically free the unmanaged resources (whatever, actually) associated with some IDisposable instance if, for example, I forgot to write using statement?

Usually, but not necessarily. The author of a disposable resource needs to do the right thing.

Obviously, I don't know when this would happen, but is it fine to leave the IDisposable to the GC when I don't care about those resources and I'm fine with that they will be disposed eventually?

Your question presupposes a falsehood. The garbage collector never calls Dispose, ever. Rather, the garbage collector calls the destructor (or "finalizer" if you prefer). It is the destructor which might or might not call Dispose for the forgetful user.

Your question also indicates a bad attitude. You might not care if the resources are freed late but another program certainly might care! What if your customer is running two programs that both try to access the same unmanaged resource, one written by you and one written by someone else? Be a good citizen; release your scarce resources as soon as you are done with them so that other programs can use them. That's the real purpose of "using" -- it's to be polite by ensuring that scarce resources are reclaimed quickly.

A correct implementation of the Dispose pattern will ensure that the destructor cleans up the unmanaged resources if the user forgets to call Dispose, and will ensure that the destructor does NOT clean up the resources if they remember.

If you are the person writing the implementation of Dispose for a class that owns unmanaged resources it is your responsibility to get the destructor code right for the case where the user does not call Dispose correctly. The correct way to write this code is extremely well documented; follow the pattern. See Jon's comments for some helpful links.

Note also that if you are writing such a class then you are required to also make it work in scenarios in which it is impossible for the user to call Dispose. For example, suppose the constructor allocates two unmanaged resources, and between the allocation of the first and second, an exception is thrown and caught outside of the constructor. There's then no way for the user to ever call Dispose because the assignment of the new object reference happens after the constructor runs successfully, and the constructor never finished running successfully. How is the first unmanaged resource freed? Only the destructor can free it. The destructor has to be robust in the face of such scenarios; the object destructed might never have been fully constructed so you cannot rely on any invariant of the constructor.

OTHER TIPS

Yes, they would be cleaned eventually. You only need to use using (heh..) when you need deterministic resource cleanup, like for GDI, Sql and other system handle-based code, or for potentially memory-heavy objects like DataTable.

Edit: This is assuming you implemented the Dispose pattern right and have your destructor call Dispose.

If an object implements the IDisposable interface correctly, by including a conditional call to the Dispose method in the finalizer, then the GC will trigger disposal of the object during a collection (via the finalizer).

There are things that cause this not to happen, but if the standard pattern is followed, then it should work in most cases.

If the object does not include disposal code in the finalizer, then all bets are off. The unmanaged resources may remain undisposed until the sun supernovas.

No, not necessarily. It depends on how you've got the unmanaged resources.

If you've got a direct handle to the unmanaged resources (probably an IntPtr) then you should either have a finalizer or use SafeHandle... otherwise you definitely could leak unmanaged resources.

If your type just has a reference to something like a FileStream, then you should expect that that type will have a finalizer.

Now it's pretty rare to need direct access to unmanaged resources from within your type, and if you're using framework types they really should clean up appropriately (but non-deterministically). Still, it's possible.

Any IDisposable in the system libraries will dispose itself when finalized (or at least, will take most of the same steps as disposing would).

There's no guarantee about third-party stuff -- if you're using an interface to some C library that gives you handles, for example, those handles might not be cleaned up til the library is unloaded (which tends to only happen at app exit). But it's common enough to forget to use Dispose or using (or to not even know or care that a certain type is disposable), that any .net library that didn't account for it is pretty badly written, IMO.

When an object is created, if it overrides Object.Finalize, the system will add it to a list of objects with registered finalizers. Objects on that list, and objects directly or indirectly referenced by them, will be ineligible for elimination unless or until GC.SuppressFinalize is called on them, or they are otherwise removed from the list. If the system notices that such an object would be eligible for elimination but for its existence on the list of finalizable objects, the system will remove if from the list of objects with registered finalizers and add it to a list of objects which should have their Finalize routine called as soon as convenient. Whenever this latter list is non-empty, the system will execute the Finalize routines of objects there.

Note that the Garbage collector doesn't actually Dispose anything--all it does is call the Finalize routine of objects which have registered for finalization. Although many types of objects have Finalize routines which can ensure cleanup if they are wrongfully abandoned, finalization can be fraught with peril. Objects will seldom be finalized at exactly the right time; they'll often not be finalized until long after they've been abandoned, and in some cases they may be finalized while their resources are still in use. It's thus wise to avoid relying upon finalizers. There are some occasions when it's necessary, but they're almost always icky.

BTW, note that if objects of a certain class directly subscribe to events from objects with a longer useful life, neither the former objects (event subscribers), nor any objects to which they hold direct or indirect references, will become eligible for elimination or finalization until the latter objects do. While one might argue that all classes should clean up after themselves if they are abandoned, ensuring that an event subscriber can find out that's been abandoned requires the creation and use of wrapper objects. This will add considerable complexity and impair performance in the case where the class is used properly. Trying to clean up events with a finalizer when not using wrapper objects would be pointless; the class with dangling events wouldn't be eligible for collection until the event publisher became eligible, and once that happened it wouldn't matter whether the former class unsubscribed or not.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top