views:

206

answers:

7

I am confused about garbage collection process on objects.

object A = new object();
object B = A;        
B.Dispose();

By calling a Dispose on variable B only, the created object will not be garbage collected as the object is still has referenced by A.

Now does the following code work same as above?

public static image Test1()
{
    Bitmap A = new Bitmap();
    return A;
}

Now I call this static function from some other method.

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 

The static function Test1 returned a reference to the Bitmap object. The reference is saved in another variable B. By calling a Dispose on B, the connection between B and object is lost but what happens to the reference that is passed from Test1. Will it remain active until the scope of the function TestB is finished?

Is there any way to dispose the reference that is passed from the static function immediately?

+9  A: 

Dispose does not garbage collect. You can't explicitly garbage collect a particular object. You can call GC.Collect() which requests that the garbage collector runs, but that's not the same. Calling Dispose doesn't even "disconnect" the object from a particular variable, in fact... while that variable remains live (up to the last time the JIT can detect that it will ever be read again) it will prevent the object from being garbage collected.

An object won't be garbage collected until it's no longer referenced by anything. Admittedly this can be earlier than you might think in some extreme cases, but you rarely need to worry about those.

It's worth being aware that Dispose and garbage collection are very different things. You call Dispose to release unmanaged resources (network connections etc). Garbage collection is solely to release memory. Admittedly garbage collection can go through finalization which may release unmanaged resources as a last resort, but most of the time you should be disposing of unmanaged resources explicitly.

Jon Skeet
As an addendum, you should *never* rely on finalizers, as they may never run. At best, they can be "last resorts" that will try to clean up resources if the program forgot to explicitly dispose of them properly.
siride
+11  A: 

I may be off, but you seem to have a misunderstanding of Dispose and garbage collection. An object will be garbage collected once all references to it are gone, in a non-deterministic way. Dispose will usually get rid of the unmanaged resources, so the object is ready to be garbage collected. In your first example, you Disposed the object, theoretically making it unusable, but it still exists on the heap and you still have a reference to it, both A and B. Once those go out of scope, the garbage collector may reclaim that memory, but not always. In example 2, a Bitmap A is placed on the heap, then you return a reference of it, and set B to that reference. Then you dispose it and B goes out of scope. At that point no more references to it exist, and it will be garbage collected at a later point.

Yuriy Faktorovich
Thanks for your response. I should have made my question more clear. I am aware that by calling Dispose(), GC will not free the memory immediately, but it will remove the reference to the object from finalizable queue so that the object will not move to next Gen. In the second example how do we call dispose on the reference passed by the function immediately after use? If we cannot dispose the reference passed by the static function, it will move to next Gen and there will be more delay for freeing the resource.
kishore
@kishore: When you say dispose the reference, it is very confusing what you mean. The reference is a pointer on the stack to the object on the heap, at least in this case. You Dispose of the unmanaged resources in the instance on heap.
Yuriy Faktorovich
Sorry for the confusion. So is there any way to remove or clear the reference that is passed by the function so that it will not point to the object on the heap?
kishore
@kishore: Well once it goes out of scope, it is popped off the heap. Now B is a copy of A which is pointing to the same instance on the heap. What I think you'd like to do, and correct me if I'm wrong, is to make sure the instance is Disposed in Test1. Which is not possible. But generally if your class has Disposable objects, you can mark it IDisposable, so anyone using should in theory call Dispose when they are done with it, and you will Dispose things like Bitmap in your Dispose method.
Yuriy Faktorovich
@Yuriy surely you meant "popped off the *stack*" not the heap.
siride
@siride You're, don't know how that got in there.
Yuriy Faktorovich
+3  A: 

Dispose() doesn't have anything to do with garbage collection. All it does is allow deterministic release of resources, but you have to call it explicitly. The object you call it on does not get garbage collected when you call Dispose(). It will be eligible for garbage collection when all the references to it are gone.

siride
+5  A: 

It happens that Raymond Chen has just written a series of blog posts describing aspects of .NET garbage collection. This post most directly relates to your question (when are objects garbage-collected?).

Daniel Pratt
I look forward to CLR week every year :)
BioBuckyBall
I was going to post a link, but I was feeling a bit lazy this morning. He's had some great posts on GC-related topics.
siride
@Daniel Thanks for sharing the post.
kishore
+1  A: 

Ok for starters Dispose != Garbage Collected. You can call dispose and never have it Garbage collected, because a "Disposed Object" can still have references to it. The dispose method is used to "Tidy Up" the object before the CG runs (close open db connections, or file connections etc.).

object A = new object();
object B = A;        
B.Dispose();

In this instance B.Dispose is calling the dispose method on A, because B is referencing the object in variable A. Neither will be CGd, because they haven't fallen out of scope yet.

public static image Test1()
{
    Bitmap A = new Bitmap();
    return A;
}

What is happening here is that you are creating object A and returning it, so when you leave Test1, A is most likely being referenced by another variable in the calling method. This means that even though you have left the method, A is still rooted (most likely) and won't be CG'd until the calling method is done with it.

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 

Here B is being created and calling dispose. This does not mean that it will be gargable collected. Once the program leaves the method, B falls out of scope meaning that it can be collected next time the GC is called.

When to use Dispose

Kevin
+2  A: 

Many good answers here but I also like to point that the reason that people thought you needed IDisposable is that a GC should really be named MemoryCollector or even ManagedMemoryCollector. A GC isn't particular smart when it comes to collect non managed memory resources such as files, db conns, transactions, windows handles and so on.

One of the reason is that a managed object might have an unmanaged resource that takes several gigs of ram but to the GC it looks like 8 bytes or so.

With files, db conns and so on you often wish to close them as soon as possible to free up unmanaged resources and avoid locking issues.

With windows handles we have thread affinity to worry over. As a GC runs in a dedicated thread that thread is always the wrong thread for freeing windows handles.

So GC helps alot to avoid leaking managed memory and reduce code clutter but one still should release unmanaged resources ASAP.

using () statement is a blessing.

PS. Quite often I implement IDisposable even though I don't have any direct unmanaged resources, its importsnt though to inform all member variables that implement IDisposable that Dispose been called.

FuleSnabel
A: 

It may be worth noting that calling Dispose may, in fact, do nothing at all. It gives the object a chance to clean up resources such as database connections and unmanaged resources. If you have an object that contains an unmanaged resource such as a database connection, Dispose will tell the object it is time to clean up those references.

The fundamental question in garbage collection is, "Can this object be reached?" As long as there is on object on the stack that has a reference to your object (or there is a reference to this object somewhere in the object hierarchy), the object won't be garbage collected.

Example:

ObjA creates an ObjB, which creates an ObjC. Obj C will not be garbage collected until it is no longer referenced by ObjB, or until ObjB is no longer referenced by ObjA, or until there are no objects that retain a reference to ObjA.

Again, the question to ask is, "Can this object currently be referenced by anything in the code?"

Jason
I should also have mentioned that, just because an object isn't referenced, doesn't mean it will be immediately collected. The garbage collector makes decisions based on how long an object's been alive, how much memory it consumes, and memory pressure in the system to determine what to collect and when. That takes a little more understanding of the garbage collector in your system to really optimize memory use. But for a beginner in GC, it is safe to assume the memory is owned by the garbage collector once the object can no longer be reached.
Jason
-1 because this post confuses GC and the purpose of Dispose(). It is true that Dispose() is there to clean up unmanaged resources. But it is called deterministically and explicitly by your code. It will never be called by the garbage collector and calling Dispose() will never result in the object being garbage collected.
siride