Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF WriteableBitmap Memory Leak?

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();
}
like image 385
Mario Avatar asked Aug 26 '09 12:08

Mario


2 Answers

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

like image 92
Bjarke Avatar answered Oct 03 '22 20:10

Bjarke


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().

like image 45
Eamon Nerbonne Avatar answered Oct 03 '22 21:10

Eamon Nerbonne