I am comfortable with how to implement 开发者_开发问答IDisposable..
However I'm not clear as to the exact consequences of not implementing this properly. Is it a case that unmanaged resources will never be cleared thus causing memory leaks or will the memory eventually get recycled anyway, just not in a timely manner?
It depends.
If the object in question fails to implement IDisposable, but does still implement a finalizer correctly, the resources will eventually get cleaned up.
However, if it doesn't properly implement a finalizer, AND it's wrapping an unmanaged resource, that resource will be leaked. This is more often a resource leak (ie: leaking a HANDLE stored as IntPtr) more than a traditional "memory leak" (though, of course, the object being pointed to does still use memory).
will the memory eventually get recycled anyway?
One point here... IDisposable has nothing to do with memory - it's about resources. These resources often use memory of their own, but implementing IDisposable does not cause your garbage collector to reclaim memory more quickly.
It depends entirely on what te implementation is, of course.
An incorrect dispose on a SqlTransaction could lead to excessive long blocking, for example - impacting multiple machines and users. An incorrect dispose on a SqlConnection could cause connection saturation and inability to connect. These are not just memory (etc) issues.
IIRC a missing graphic (pen/brush/whatever) dispose was responsible for a VS crash bug - GC didn't happen because there was no memory pressure, so instead it simply saturated the GDI handles and broke.
An incorrect file/stream dispose could cause exceptions due to a file bring unavailable for reading/writing - potentially losing data.
With unmanaged resources not properly handled, anything is possible.
Instead of thinking in terms of some vaguely-defined "resources", think of IDisposable as meaning "This object manipulates something outside itself (and possibly even outside the computer!) in a way that needs to be cleaned up, while the information necessary for such cleanup still exists." A finalizer which fires essentially says "Nobody else is using this stuff anymore, and I'm the only one who knows about it; I'd better clean it up because nobody else is going to."
It is dangerous to assume that finalizers will magically take care of things; while many objects can be safely abandoned, many others cannot. In some cases, it will be easy for an object to detect that it has been abandoned and clean up appropriately. In some other cases, it may be so difficult as to be impractical. Consider an object which is supposed to count how many times the word "quack" appears in a long-lived data stream. If the creator of the object has forgotten about it, and nobody is every going to query the count, the object may as well go away. Unfortunately, since the data stream holds a reference to the counting object (so as to let it know when data comes in), the counter object won't go away. If code creates a counter, then forgets about it, then creates another one, forgets about it, etc. this could become an unbounded memory leak.
A class that holds unmanaged resources should ensure that they are cleaned up during finalization. However, this only happens when the garbage collector gets around to it.
Not calling Dispose means waiting for the garbage collector to need memory before the resources are released.
The latter of the two. Just not in a timely manner.
The importance of this depends on the resources you are allocating. This is why you are more likely to see IDisposable interfaces on objects that open files and reference other, more crticital, resources.
Yes, unmanaged resources will never be released. (This assumes that the IDisposable
types in question don't implement a "fallback" finaliser. If they do then the finaliser should sort things out... eventually.)
However, it's not just unmanaged memory allocations that you need to worry about; it's any unmanaged resources. For example, if you don't properly dispose of your database connections then you might find that the connection pool quickly gets exhausted.
Another potential problem with not implementing the disposable pattern properly - it is very easy to accidentally call .Dispose() more than once. If your Dispose method does not check for successive calls to it, and (eg.) attempts to free up an unmanaged resource more than once, you might end up with some unrecoverable error, or unexpected behaviour.
精彩评论