views:

539

answers:

7

In the following c# code, how do I get rid of the objects when it's no longer useful? Does it get taken care of automatically, or do I need to do something?

public void Test()
{
   object MyObject = new object();

   ... code ...
}
+18  A: 

Automatically. When MyObject goes out of scope (at the end of Test), it's flagged for garbage collection. At some point in the future, the .NET runtime will clean up the memory for you

Edit: (I should point out for the sake of completeness that if you pass MyObject somewhere, it gets passed by reference, and will not be garbage collected - it's only when no more references to the object are floating around that the GC is free to collect it)

Edit: in a release build, MyObject will usually be collected as soon as it's unused (see my answer for more details --dp)

Matt
This answer makes the whole process sound more active than it is. Nothing "flags" the object when it leaves scope - it just doesn't count when the GC tries to find objects *not* to throw away.
Jon Skeet
Oh, and MyObject is only passed by reference using "ref". Otherwise it's passed by value, but the value *is* a reference. They're not the same thing.
Jon Skeet
Regarding dp's edit - becoming *eligible* for GC early isn't the same thing as "will usually be collected as soon as it's unused" - you've still got to wait for the GC to perform a collection.
Jon Skeet
@dp : edit to highlight your own post? That's a first.
Learning
+1  A: 

It gets taken care of automatically.

Justice
+2  A: 

In optimized code, it is possible and likely that MyObject will be collected before the end of the method. By default, the debug configuration in Visual Studio will build with the debug switch on and the optimize switch off which means that MyObject will be kept to the end of the method (so that you can look at the value while debugging). Building with optimize off (debug doesn't matter in this case) allows MyObject to be collected after it's determined to be unused. One way to force it to stay alive to the end of the method is to call GC.KeepAlive(MyObject) at the end of the method.

dpp
+4  A: 

The other answers are correct, unless your object is an instance of a class which implements the IDisposable interface, in which case you ought to (explicitly, or implicitly via a using statement) call the object's Dispose method.

ChrisW
+1  A: 

Typically garbage collection can be depended on to cleanup, but if your object contains any unmanaged resources (database connections, open files etc) you will need to explicitly close those resources and/or exceute the dispose method on the object (if it implements IDisposable). This can lead to bugs so you need to be careful how you deal with these types of objects. Simply closing a file after using it is not always sufficient since an exception before the close executes will leave the file open. Either use a using block or a try-finally block.

Bottom line: "using" is your friend.

Jim Petkus
+2  A: 

This will force the garbage collector to get rid of unused objects.

GC.Collect();
GC.WaitForPendingFinalizers();

If you want a specific object to be collected.

object A = new Object();
...
A = null;
GC.collect();
GC.WaitForPendingFinalizers();
kthakore
No need to set it to null if it's a local variable and not used in the rest of the method. (Assuming you're running in release mode.)
Jon Skeet
+2  A: 

The short answer is: unless it has unmanaged resources (file handles etc) you don't need to worry.

The long answer is a bit more involved.

When .NET decides it wants to free up some memory, it runs the garbage collector. This looks for all the objects which are still in use, and marks them as such. Any local variable (in any stack frame of any thread) which may still be read counts as a root as do static variables. (In fact I believe that static variables are referenced via live Type objects, which are referenced via live AppDomain objects, but for the most part you can regard static variables as roots.)

The garbage collector looks at each object referred to by a root, and then finds more "live" references based on the instance variables within those objects. It recurses down, finding and marking more and more objects as "live". Once it's finished this process, it can then look at all the rest of the objects and free them.

That's a very broad conceptual picture - but it gets a lot more detailed when you think of the generational model of garbage collection, finalizers, concurrent collection etc. I strongly recommend that you read Jeff Richter's CLR via C# which goes into this in a lot of detail. He also has a two part article (back from 2000, but still very relevant) if you don't want to buy the book.

Of course all this doesn't mean you don't need to worry about memory usage and object lifetimes in .NET. In particular:

  • Creating objects pointlessly will cost performance. In particular, the garbage collector is fast but not free. Look for simple ways to reduce your memory usage as you code, but micro-optimising before you know you have a problem is also bad.
  • It's possible to "leak" memory by making objects reachable for longer than you intended. Two reasonably common causes of this are static variables and event subscriptions. (An event subscription makes the event handler reachable from the event publisher, but not the other way round.)
  • If you use more memory (in a live, reachable way) than you have available, your app will crash. There's not a lot .NET can do to prevent that!
  • Objects which use non-memory resources typically implement IDisposable. You should call Dispose on them to release those resources when you're finished with the object. Note that this doesn't free the object itself - only the garbage collector can do that. The using statement in C# is the most convenient way of calling Dispose reliably, even in the face of an exception.
Jon Skeet