9

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?

Azhar
  • 20,500
  • 38
  • 146
  • 211
kishore
  • 719
  • 9
  • 29
  • 3
    Garbage collection is not reference counting. – tc. Aug 13 '10 at 17:45
  • The whole point of garbage collection is that you don't have to care about when or if memory is being released. In principle, on a system with vast reserves of memory, garbage collection could _never_ happen, simply because it would more efficient to just let everything be cleaned up when the application is terminated. – Dan Bryant Aug 13 '10 at 18:21

7 Answers7

18

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 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 Aug 13 '10 at 19:33
16

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
  • 67,283
  • 14
  • 105
  • 142
  • 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 Aug 13 '10 at 18:16
  • 1
    @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 Aug 13 '10 at 18:36
  • 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 Aug 13 '10 at 19:25
  • 1
    @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 Aug 13 '10 at 19:56
  • @Yuriy surely you meant "popped off the *stack*" not the heap. – siride Aug 13 '10 at 22:06
  • @siride You're, don't know how that got in there. – Yuriy Faktorovich Aug 13 '10 at 23:21
5

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
  • 12,007
  • 2
  • 44
  • 61
3

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
  • 200,666
  • 4
  • 41
  • 62
2

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.

1

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

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
0

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
  • 951
  • 5
  • 11
  • 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 Aug 13 '10 at 19:25
  • -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 Aug 13 '10 at 19:36