开发者

C# Dispose() -clarification

When i call object.Dispose(); Will CLR immediately destroy the object from memory or mark the object for removal in it's next cycle?.

We are calling GC.SuppressFinalize() immediately after Dispose(),Does it mean ,"Don't collect the object again for dispose,because it is already submitted to displose".

Act开发者_StackOverflow中文版ually which generation is responsible for destruction ,i guess generation 2.


First of all, IDisposable.Dispose and GC isn't about the same thing.

GC will clean up memory usage, IDisposable.Dispose is used to deterministically free resources, like file handles, database connections, network connections, etc.

Let's tackle finalization first.

If an object declares a finalizer, the object is treated specially when GC comes around to freeing it from memory. The object is, instead of just being freed at once, put on a separate list.

In the background, a finalization thread is running through this list and calling the finalizer methods of the objects on this list. Once the finalizer method has been called, the object is removed from the list.

The point here is that while the object is on this list, it is not eligible for collection. This means that an object that has a finalizer, once it becomes eligible for collection, will temporarily transition into a state where it is no longer eligible for collection, but pending finalization. Once the object is discovered again, after the finalizer has run and it has been removed from this list, then it is being freed from memory.

GC.SuppressFinalize is just a way for an object to say that "the finalizer no longer needs to run, if you discover that this object is eligible for collection, just free it at once".

IDisposable.Dispose, on the other hand, once implemented by an object, is not entirely related to the garbage collector. There is nothing built into the GC system that will ensure that the Dispose method is called. This means that an object that has a Dispose method can easily be freed without Dispose ever being called.

Also, calling Dispose does not in any way make the object eligible for collection. The only way to make an object eligible for collection is to remove all strong references to it, usually by letting local variables going out of scope (method returns) or by removing any references to the object from other objects (like lists, event handlers, etc.)

The "link", if you want to call it that is that an object that internally has such a resource will typically implement a finalizer, if the resource is unmanaged. If the resource is a managed one, like a FileStream object, then that object will take care of finalization, if needed, by itself. However, if you're holding on to unmanaged resources, like file handles you have retrieved via P/Invoke, then you should implement a finalizer.

Typically, both the finalizer and IDisposable.Dispose for that object will clean up that resource, and its then typical for Dispose to call GC.SuppressFinalize to say that "I've taken care of it, you can just free the object if it is eligible for collection."

However, if you just call Dispose, but still keep a reference to the object (event handler, static fields, local variables, etc.) then the object is not yet eligible for collection and will not be freed.

So, to summarize:

  1. Calling Dispose is typically done to free up resources (unmanaged or managed). It does not in any way influence whether GC can collect the object, or when it will be done.
  2. The only way to make an object eligible for collection is to explicitly lose all strong references to it.
  3. A finalizer is called by GC, usually implemented to free unmanaged resources.
  4. An object that is eligible for collection, but has a finalizer, will temporarily be put on a list (and thus no longer be eligible for collection) until the finalizer has been executed

Bonus questions:

What do you think will happen if:

  1. A finalizer hangs? (There is typically (that is, to my knowledge) only one finalizer thread, if it hangs, what happens to the rest of the objects on that list?)
  2. An object makes itself uneligible for collection as part of its finalizer (typically by inserting itself into a static field). The finalizer has run, and there is a mark for that, so the finalizer will not automatically re-run once the object again becomes available for collection. There are other methods in the GC object that can re-register it for finalization though.

Hope this answered your question, if not, please leave a comment or clarify your question and I'll edit my answer.


Dispose is a normal CLR method that happens to usually call GC.SuppressFinalize. The garbage collector has nothing to do with it, and calling Dispose has no special significance for the GC.

If Dispose calls GC.SuppressFinalize(this), the GC will not run the finalizer when it collects the object.
However, that does not mean that the object will be collected sooner.


No, Dispose doesn't cause the garbage collector to collect an object. The reason you see GC.SuppressFinalize() in a lot of Dispose methods is because a lot of disposable classes implement a finalizer to assure disposal. I'll explain.

If I implement a class that holds a critical resource, and I want to make sure (well, almost sure) that my class is disposed of properly, then I may not just rely on consumers of my class to call Dispose or use a using. Instead, I may implement a finalizer, which, in most cases, will get called when the GC collects my objects. In the finalizer, I'll force a call to Dispose.

But an object with a finalizer is more complicated for the garbage collector. It will hang around longer, taking more memory, and take more time to process when it's collected.

So if the user does remember to dispose properly, then we can tell the GC that it doesn't need to call the finalizer for this object.


The generation of an object refers to how many garbage collections it "survived" (2 being the highest). When an object is created it is in generation 0 and only if the object was reachable or "live" (had strong references to it) at the time of collection, will it be propoted to next generation.

This does not include generation 0 objects with complex finalizers as finalisers get run on a seperate thread and once completed, get collected in the usual way. They do not get promoted.

Collection of a generation 2 object could take a really long time as the GC may only need to collect generation 0 objects to free enough space on the heap. To force a full collection call GC.Collect().

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜