views:

687

answers:

3

Hello, everyone!

I'm trying to figure out how to release a WriteableBitmap memory.

In the next section of code I fill the backbuffer of a WriteableBitmap with a really large amount of data from "BigImage" (3600 * 4800 px, just for testing) If I comment the lines where bitmap and image are equaled to null, the memory it´s not release and the application consumes ~230 MB, even when Image and bitmap are no longer used!

As you can see at the end of the code its necessary to call GC.Collect() to release the memory.

So the question is, what is the right way to free the memory used by a WriteableBitmap object? Is GC.Collect() the only way?

Any help would be great.

PS. Sorry for my bad english.

private void buttonTest_Click(object sender, RoutedEventArgs e)
{
            Image image = new Image();
            image.Source = new BitmapImage(new Uri("BigImage"));

            WriteableBitmap bitmap = new WriteableBitmap(
                (BitmapSource)image.Source);

            bitmap.Lock();

            // Bitmap processing

            bitmap.Unlock();

            image = null;
            bitmap = null;

            GC.Collect();
}
A: 

Forcing a GC without setting image and bitmap to null won't clean them up because they are still being referenced locally and are thus considered root references. This is nothing specifically to do with the WriteableBitmap and more a question of how GC works.

If you don't set them to null and don't force a garbage collection then they will be collected once the method exists and a GC occurs. That is recommended above forcing the collection yourself because you're probably hurting performance rather than helping it.

HTH, Kent

Kent Boogaart
Thank you both for your help.The problem is that the garbage collector does not seem to collect the memory used by image and bitmap. If I comment the lines where they are assigned to null and once the method finishes execution the memory used by the whole application remains ~234 MB.Seems like a really troublesome behavior.Thank you again.
Mario
Remains for how long? Are you sure the garbage collector is actually trying to collect? Open up perfmon and watch the GC counters to see whether it is actually trying to collect. If not, you've got nothing to worry about - there is no memory pressure so the GC isn't required.
Kent Boogaart
Thanks for your help and patience. I've seen GC performance counters, and there is a low % of time spent in GC, however i need som help figuring out the next data:#Bytes in all heaps 1,115,176,000#GC handles 845,000#induce GC 5.0It seems the call to GC.Collect() it's not necessary, but the null assignation of both object (image and bitmap) is, since when they are ommited the used memory remains at ~234MB until the application is closed.
Mario
To be garbage collected, the references to the images must be overwritten (e.g. by the null reference), or must cease to exist (say, when the method ends). The garbage collector isn't deterministic - don't worry about more than these basic rules. If the memory *can* be freed by an explicit GC.Collect(), you're fine- let the GC determine the timing, and worry about memory issues once you run into them.
Eamon Nerbonne
A: 

In general, memory should eventually be freed automatically as needed.

However, for that to happen, you need to be sure that the object is truly unused: No references to the object may exist anywhere, including references which "aren't used anymore". So, in particular, if you place your WriteableBitmap and original BitmapSource in variables of a long-lived class, they won't be released until the container is.

Also, WPF uses a retained GFX model: when you render, you're actually just storing instructions on how to render. The "instructions" on how to render a bitmap include a reference to the bitmap - so if you ever render a large bitmap, then for a while (at least as long as it's on screen - even if the version on screen is tiny) those images will be retained.

In practice; store references to these bitmaps only where they are needed, and if the context in which they live is long-lived (a long method call, or a method call generating a closure with a reference to the bitmaps, or a member of a long-lived class) then set them to null once they're no longer needed.

It is not necessary to manually free the memory; GC.Collect() should be superfluous. As a rule of thumb, only use GC.Collect during benchmarking to get an indication of memory consumption and/or to start with a clean slate. Overall performance is generally decreased by calls do GC.Collect().

Eamon Nerbonne
+1  A: 

Are you running your test on Windows XP, using .Net 3.5 SP1? If so, then it is a known problem, that will be fixed in 4.0.

See http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5d88cdf1-e992-4ad4-8f56-b5dbf92dcf1c

Bjarke