tags:

views:

769

answers:

4

We use Enterprise Library 3.0 to access Oracle DB (microsoft oracle client). What happens when I do not dispose a DbCommand instance after a stored procedure or function is called? Does .NET automatically garbage collect them? Note that we do make sure that the transaction/connection gets closed and disposed properly.

+1  A: 

Not 100% sure about Oracle, but when using SqlCommand, it must be disposed after use. You could either just call .Dispose(), or just put it in a using block, like so:


using(DbCommand cmd = new DbCommand(foo, bar))
{
     // use cmd object
}
mgroves
+7  A: 

This is a duplicate, but I don't have time to find the original.

If it implements IDisposable, and if you created it, then you need to call Dispose on it. That's why the developer of the class made it implement IDisposable.

The garbage collector does not call Dispose on all IDisposable-implementing objects.

John Saunders
What? No, that is false. The standard pattern for Dispose is to allow users to free the resources early, but still clean up in the finalizer if the method has not been called yet.
RandomEngy
See this article: http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspxDispose() is called in the finalizer, which will indeed run when the garbage collector gets to it.
RandomEngy
Not all users of IDisposable implement a finalizer. Not all who impolement a finalizer will follow the standard pattern. You cannot depend on the existence of a finalizer,a nd you cannot depend on Dispose being called by the garbage collector.
John Saunders
@RandomEngy -- that article implies that Dispose() will be called in the finalizer only if the finalizer calls Dispose(). Since you can't be guaranteed that any class calls Dispose in a finalizer, you should be diligent about calling it yourself.
Jeremy Frey
Yes, if you think the class you are using is not implementing IDisposable correctly, you can call Dispose yourself, just to be safe. But to say that a developer made a class IDisposable just because they want you to call dispose on it is not correct.
RandomEngy
The IDisposable interface, and "the Dispose pattern" are two different things. You do not have to implement a finalizer in order to properly implement IDisposable.
John Saunders
I never said it was the only reason to call Dispose. I said that if it's implemented, you should call Dispose. Even if, for some reason, all the classes you're using "properly implement the Dispose pattern", you can't determine how long it will be before the garbage collector gets around to collecting the resources. Even if you only use the "proper" classes, then you should call Dispose unless you want resources hanging around for an indefinite amount of time.
John Saunders
In many cases you're using a class that you know implements the Dispose pattern correctly (such as framework classes, or classes under your control). They have some unmanaged components but they are very inexpensive to keep around. Letting the garbage collector handle them is a perfectly valid option, and can yeild some nice benefits in making your code cleaner.If you have a problem with "resources hanging around for an indefinite amount of time" I don't think a language with garbage collection is for you.
RandomEngy
@RandomEngy: Whether or not a class implements the pattern "correctly" is an implementation detail and could possibly change in future versions of that class, so why take a chance? Just call Dispose and you don't have to worry about any future implementation changes.
LukeH
@RandomEngy: Any class that implements IDisposable is effectively saying "you should call Dispose when you're done". That's all IDisposable is for. If the class doesn't expect you to call Dispose then why would it implement IDisposable, rather than just doing all cleanup in the finaliser?
LukeH
@RandomEngy: this is not what you were arguing before. Either the garbage collector will always call Dispose, or not. Did you change your mind? Is this your new argument? If so, then please add an answer clearly showing an example of when it is better to ignore this clear best practice. Why is it better than simply calling Dispose or implementing a using block?
John Saunders
@John Saunders: You get cleaner code, that's the advantage. Yes, there's a risk that the class might stop using the correct dispose pattern, but I think that chance is rather small with framework classes and classes you control.@Luke: the class may implement IDisposable to give you the option of mopping up the resources early. It might not be imperative in your implementation that you take advantage of that capability.
RandomEngy
@RandomEngy: if the code is incorrect, then it's not cleaner. Sorry, man, this is just plain dangerous. When weird stuff starts happening in code that "used to work", first thing I look for is failing to use Dispose properly, followed by failure to handle exceptions properly. You're giving Murphy an opening you don't need to give.
John Saunders
+5  A: 

Reflector doesn't indicate that OracleCommand specifically overrides Dispose (from System.ComponentModel.Component's implementation, anyway), so chances are it won't hurt your application much if you don't call it.

The important thing, though, is that OracleCommand specifically implements IDbCommand, which specifically implements IDisposable. If you ever replaced your OracleCommand with another IDbCommand, then you would most likely want to use Dispose(). And while SqlCommand doesn't explicitly override Dispose(), Odbc and OleDb certainly do.

In short, since it's IDisposable, you should dispose it, just to be on the safe side.

Jeremy Frey
Thanks for the explanation.
Vivek
A: 

From the documentation for IDisposable:

The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.

Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. The consumer of an object can call this method when the object is no longer needed.

Given this, an object that implements IDisposable potentially maintains references to unmanaged resources. These resources are not released until the garbage collector comes along and collects the object. However, since you cannot know when the garbage collector will do this, disposable objects (such as OracleDbCommand) can hang around far longer than you might want them to.

If an object implements IDisposable, you should call it as soon as possible to release the unmanaged resources that it holds references to. This can be accomplished by either calling Dispose directly or by declaring it within a using block.

Mike Hofer
I read that to say that "Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams". Therefore, the GC will _not_ release these resources, ever.
John Saunders
That's precisely why a class implements IDisposable. The GC can't release them because it doesn't know about them. The class that holds those unmanaged resources must free them when the Dispose method is invoked.
Mike Hofer
But you said "These resources are not released until the garbage collector comes along and collects the object". The release of these unmanaged resources does not, in general, depend on the garbage collector at all.
John Saunders
Actually, Microsoft said that. See http://msdn.microsoft.com/en-us/library/system.idisposable.aspx. So, in truth, the correct release of those resources *does* depend on the implementation of IDisposable. The GC has no idea you've allocated an unmanaged resource; consequently, it can't release it for you. When it comes time to collect your object, you're given an opportunity to release those objects yourself, through implementation of IDisposable.
Mike Hofer
You are not given a change to release the objects unless you have implemented a finalizer. Someone who uses an object implementing IDisposable cannot depend on whether this has been done. The only way to be certain to get all unmanaged resources released is to explicitly call Dispose yourself, and not assume that GC will take care of it. The usual way of ensuring Dispose is called is by a using statement.
John Saunders