开发者

Garbage Colletion with IDisposable

I was talking with a person about using() statement.

He said if we do NOT use using() statement for something like a StreamWriter, if any exception happens, the resource will NEVER get collected.

I do understand to use using() statement, but I don't agree that the resource will never be collected. I think using() statement will call dispose() method at the end, which can make the collection much faster. However, even if 开发者_Python百科we don't use using(), we don't call dispose(), the resource can still be collected by gabage collection, although it may take much longer time.

Who do you agree with?

ps. I know what you all are saying. It's important to use using() statement. I just want to find out if the resource will definitely never get collected if we don't do it?


Let's be clear on this. Suppose the resource in question is a file handle. The garbage collector knows nothing about the file handle or how to free it. The file handle is just an integer.

If the StreamWriter that is holding on to the file handle gets garbage collected then the garbage collector will put the object onto the finalization queue. When the finalization queue runs, it will call the finalizer of the object, and that is what releases the file handle.

Is that all clear? The garbage collector does not free the resource; the only resource the garbage collector knows about is objects in memory. Before the object is freed it is finalized, so it is the object itself that knows how to free the resource.


using(x) is a deterministic pattern. It ensures that Dispose() is called on the implementor when a particular point in the execution flow is passed. The GC on the other hand is not deterministic, because you don't know exactly when the object will be actually disposed. using ensures that the object will execute its cleanup code (whatever that is) when you expect it to, rather than some time in the future.


If there's no reference to that StreamWriter anymore it will eventually be garbage collected, but it depends on the Garbage Collector when that is - it's not deterministic, so you should always use using blocks when you can.


You should always call Dispose() when you are done using an IDisposable object. A using statement is a great tool for making sure you obide by this rule.

The purpose of IDisposable is to allow classes to dispose of allocated unmanaged resources which will not be automatically cleaned up by garbage collection.

If you use an IDisposable object without calling Dispose() when you are done, you run the risk of never disposing of the resource properly, even after it has been garbage collected.

This is the reason why the using statement exists; it provides a convenient syntax for using IDisposable objects and defines a clear scope in which these objects are usable.

Note also that the garbage collector never calls Dispose() itself, but note also that it is recommended to follow the Finalize/Dispose pattern as documented on MSDN. If an object follows the Finalize/Dispose pattern, Dispose() will be called when the GC calls the finalizer.


I was talking with a person about using() statement. He said if we do NOT use using() statement for something like a StreamWriter, if any exception happens, the resource will NEVER get collected.

The using statement has nothing to do with garbage collection. As soon as an object has no live references it becomes eligible for garbage collection.

I do understand to use using() statement, but I don't agree that the resource will never be collected.

Oh, then you're right.

I think using() statement will call dispose() method at the end, which can make the collection much faster.

It may or may not make the collection faster. It is typical for a dispose method to call GC.SupressFinalize(object), which means that the finalizer will not be called when the object is garbage collected. Instead, the object will simply be collected. So this could make the collection faster.

If you intend to say that it causes the object to be collected immediately rather than later, then that would be incorrect. Eligible objects are collected whenever the garbage collector gets around to it, never before, and an object become eligible as soon as it has no live references, which the using statement has little effect on. Actually, since the finally block of the using statement contains a live reference, I can imagine scenerios in which it might increase the lifetime of the object, but this effect is not a consideration, since controlling an object's lifetime is not the point of a using. Deterministic disposal of unmanaged resources is the point of a using statement.

However, even if we don't use using(), we don't call dispose(), the resource can still be collected by gabage collection, although it may take much longer time.

Again, using and Dispose do not typically effect the lifetime of an object. It only affects the state of unmanaged resources (assuming the Dispose method is implemented correctly). You are correct that the object will still be collected.


using is essentially the same as the following (Check the IL of both if you doubt it):

 try
 { 
      IDisposable o = new Object();
 }
 finally
 {
      o.Dispose();
 }

As long as the object in question implements IDisposable, the Dispose() method will be called and the resource, pending something stupid coded in Dispose() will be Garbage Collected. When? Not a question I can answer.

Is it possible that an item will never be GCed. Well, never is a long time, but theoretically possible if it gets beyond the first generation and just sits there. A problem? No, if the memory is eventually needed, it will be cleaned. Often seen, incorrectly, as a memory leak? Most certainly.


If a StreamWriter is created with a Stream that will be used by other code even after the StreamWriter has been abandoned, one must not call Dispose on the StreamWriter. If the stream will be abandoned by its owner after being given to a StreamWriter, then for correctness one must call Dispose on the StreamWriter.

In retrospect, StreamWriter should probably have had a do-nothing IDisposable implementation, but had an descendant class StreamOwningWriter whose implementation would dispose the passed-in stream. Alternatively, it could have had a constructor parameter and property to indicate whether it should dispose the stream when its own Dispose method is called. Had either of these approaches been taken, then the correct behavior would always have been to call Dispose on a StreamWriter (and let the "StreamWriter" (which could be either a StreamWriter or a StreamOwningWriter) worry about whether the Dispose should actually do anything).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜