views:

309

answers:

4

For example, in the below code an 'image'object will be created and then garbage collected at some unknown point in the future

void MyFunction() {

    Bitmap image = RetrieveImage();
    DoSomething(image);
}

What about

void MyFunction() {

    DoSomething(RetrieveImage());

}

In this case is the object garbage collected once it moves out of scope i.e. After the end of MyFunction. If not is there somewhere to enforce this?

+19  A: 

No. In fact, you don't really want it to be garbage collected - prompting the garbage collector very frequently will reduce performance.

What you do want is to dispose of the unmanaged resources in a timely manner - and that's where IDisposable comes in, along with the using statement:

void MyFunction()
{
    using (Bitmap image = RetrieveImage())
    {
        DoSomething(image);
    }
}

That will call image.Dispose() as it leaves the using statement, whether or not DoSomething threw an exception.

You do have to use the extra variable though - unless you change DoSomething to take a Func<Bitmap> instead, so instead of:

void DoSomething(Bitmap image)
{
    // Code here
}
...
DoSomething(RetrieveImage());

you'd have:

void DoSomething(Func<Bitmap> imageProvider)
{
    using (Bitmap image = imageProvider())
    {
        // Code here
    }
}
...
DoSomething(() => RetrieveImage());

Note that that doesn't give the opportunity to pass in a bitmap without it being disposed - which could be a problem if you want to use it again later. Still, it's a nice technique to at least know about.

EDIT: As mbeckish has pointed out in his comments, there isn't very much benefit here over just disposing of the bitmap within RetrieveImage. Here's a variant on the pattern though:

public void ApplyToEachLineInFile(string file, Action<string> action)
{
    using (TextReader reader = File.OpenText(file))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            action(line);
        }
    }
}

Here the "acquire and dispose" logic is encapsulated, without the caller worrying about it - but the caller can still be very flexible in terms of the complexity of logic they pass in.

Jon Skeet
Nice suggestion of passing in the provider delegate. That's a very useful pattern in many cases.
Reed Copsey
Why is that better than DoSomething(RetrieveImage()); and dispose the bitmap in DoSomething?
mbeckish
Because if the bitmap is passed in to DoSomething, how does DoSomething know whether it's safe to dispose? What if the caller wanted to pass the bitmap to DoSomethingElse after passing it to DoSomething?
Joel Mueller
@Joel - Both my suggestion and Jon's dispose of the bitmap in DoSomething.
mbeckish
@mbeckish: My second suggestion does, but it explicitly says: "Note that that doesn't give the opportunity to pass in a bitmap without it being disposed - which could be a problem if you want to use it again later."
Jon Skeet
@Jon - Yes, and I agree that this could be a source of confusion. I was just wondering if there was an advantage to passing an image provider vs. DoSomething(RetrieveImage()).
mbeckish
@mbeckish: In the situation where DoSomething always disposed of it at the end? Possibly not a lot...
Jon Skeet
@mbeckish: Have updated answer with a better example of the pattern :)
Jon Skeet
another advantage of that pattern is that ApplyToEachLineInFile could be a static method on a class with private ctor that wraps the resource, this would mean you can force callers to use the resource safely (doesn't work if they need resource as a memebr of course)
jk
+3  A: 

Garbage collection does not happen when an object falls out of scope. Rather it is an automatic memory management function from the framework.

http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

You can force .Net to collect the garbage, but unless you are experiencing serious memory issues, I would not recommend you go down that path.

Raj More
Agreed, it's usually best to let the garbage collector perform its own tasks automatically as opposed to invoking it manually.
Jamie Keeling
A: 

You can enforce Garbage Collection with:

System.GC.Collect()

after Disposing it properly (see Jons Answer for the using() {} - Syntax).

<edit>

Don't forget (as I just did)

System.GC.WaitForPendingFinalizers();

afterwards.

</edit>

Although it is not recommended - as Jon said.

Leonidas
Calling Collect does not *guarantee* that an object which is out of scope actually gets collected. There are many interesting and bizarre scenarios in which such an object can live on a while longer. Also note that you typically should wait for pending finalizers to run if you're forcing a collection; pending finalizers run on another thread, so there could be races.
Eric Lippert
True. Thx. Should have simply copied the code we used ;)
Leonidas
+2  A: 

NOTE: You don't want to do this. The .NET garbage collector is "smarter" than you (or me, or Jon Skeet or anyone else).

try
{
    Bitmap image = RetrieveImage();
    DoSomething(image);
}
finally
{
    GC.Collect();
}

(this is assuming that none of the objects that fall out of scope implement IDisposable)

DrJokepu
Note that for this to work it is crucial that the `image` variable be declared inside the `try` statement, as given. Otherwise, the runtime may or may not consider the object unreachable, and you may end up promoting it to a higher generation, effectively preventing the object from ever being garbage-collected.
Jeffrey L Whitledge