可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Could someone explain what might happen if you don't Dispose
some IDisposable
entity (by using
or direct Dispose
call)?
Does this always result in a memory leak and if yes, are C#
memory leaks similiar to C++
memory leaks, where they could easily lead to a crash or is C#
sandbox safer from this point of view?
Thank you.
回答1:
It completely depends on the object in question.
There are fourfive reasons that an object might implement IDisposable
:
It owns native resources.
If so, it should call Dispose
in its finalizer, so all that happens if you forget to dispose it is that the native resources last longer than necessary.
If you create lots of such objects at once and don't dispose them, you may run out of native resources.
It owns managed objects that are disposable.
The objects that it owns will fall also into one of these categories; see the relevant category.
It has a long-lasting reference to itself that won't be freed naturally (eg, it handles a static
event)
The dispose method would clear this reference (eg, unregister the event handler)
If so, not calling Dispose
will cause it to last forever.
It inherits a disposable base class, such as Stream
or Component
, but doesn't actually need to be disposed. (eg, MemoryStream
)
If so, not calling Dispose
is harmless, unless the class changes in the future.
It performs some action in its Dispose
method that people should call in a using
statement (eg, using (Html.BeginForm() { ... }
)
If so, not disposing the object will defeat its entire purpose, which is to do that action.
回答2:
One distinction that is worth pointing out is that .NET manages memory, but not resources. IDisposable
is designed so that clients of classes implementing this interface can dispose resources deterministically.
Joe Duffy states the distinction pretty clearly in his post entitled DG Update: Dispose, Finalization, and Resource Management:
The CLR’s garbage collector (GC) does
an amazing job at managing memory
allocated directly to CLR objects, but
was explicitly not designed to deal
with unmanaged memory and OS-managed
resources.
回答3:
Any number of things might happen because a class if free to implement Dispose
however they choose to.
What is usually disposed is not managed resources (which usually take care of themselves) but unmanaged ones such as database connections, file locks, etc.
Generally speaking Disposed is called in the finalizer when garbage collection gets around to it, however for instance if you write to a file and you don't close it (which Dispose does) then you're preventing anything other program (including other parts of your code in the same program) from opening that file (except possibly in read-only mode).
If you hold on to database connections for longer than necessary you could hit the max open connections and stop your app from using the database.
In generally if a class implements IDisposable
it's saying that I have something that needs to be disposed, and it should be disposed as soon as possible, not waiting for the garbage collector to come around.
回答4:
The most likely effects will be resource locking (e.g. you open a file handle and don't close it - eventually the finalizer will take care of it) or exhaustion (e.g. you do drawing operations and don't dispose of the objects).
This can be a problem, especially with the latter issue, if the memory pressure isn't sufficient to cause a GC (which will kick off the finalization process) in time to use more of the resources. This leads to helpful errors as "a generic error occurred in GDI+."
Poorly written objects may leak memory if they have only a Dispose method and no finalizer, but this is a rarity. Another possibility is that the Dispose method unsubscribes from static events. This could also be a significant problem and will "leak" memory.
回答5:
Not calling .Dispose() could result in a memory leak. Otherwise, not calling Dispose() will simply result in delayed collection by the GC. Overall, the effects will completely depend on what objects are instantiated (see SLaks for a great bullet list). By implementing IDisposable
, you are taking responsibility for cleaning up your mess, so to speak.
What implementation should do is tell the GC (Garbage Collector) that it should suppress collection because you are going to take care of it. That way, when the Dispose() method is called on your IDisposable object, you should have taken care of clean up - i.e., calling Dispose() on objects within that class, clearing collections, etc.
And, FYI, the using{...}
clause can only be used on objects implementing IDisposable because at the closing bracket the Dispose() method is called automatically:
using (MyDisposableObject dispObj = new MyDisposableObject())
{
// use dispObj for some work
} // dispObj.Dispose() is automatically called here
回答6:
IDisposable is meant to wrap an unmanaged resources (i.e. not .NET memory). So if you don't dispose them, you will leak things like open database connections, Window handles, file handles, etc. depending on what type of IDisposable you're failing to dispose.
So it's not truly a memory leak, but it can lead to performance degradation and eventually a crash as you run out of the unmanaged resources.
回答7:
Some objects will, during their existence, do things to outside entities that they are expected to clean up. There is a very strong convention that such objects should whenever practical implement IDisposable and perform any required cleanup when the IDisposable.Dispose() method is called. The system allows objects to request notification if it notices that they've been abandoned, but there's no guarantee that such notifications will happen in time to be useful. Further, unless one is careful, it's possible for such notifications to fire early and try to clean up things that are still in use.
Unless you know that a particular class of IDisposable object may be safely abandoned, don't. Always clean up after yourself whenever practical. "Finalization" (the process of notifying objects they've been abandoned) is dangerous and can create many Heisenbugs. Avoid relying on it if any practical alternative exists.