views:

2079

answers:

3

I have a ListBox with a bunch of images in it (done through a datatemplate). The images are created by setting the items source:

<Image x:Name="ItemImage" Source="{Binding ImageUrl}"/>

and then they are cleared by using the listbox's Items.Clear() method. New Images are added by using the Items.Add method of the listbox.

However, memory usage just starts moving up and up and up. It is the same 300 or so small images that are getting displayed, but the memory never seems to get freed. The App starts using about 40Megs, and quickly climbs up to 700Megs. How do I free up the memory that all these images are using?

EDIT: One thing I forgot to mention, the images (which are about 4-5k each in size) are being loaded over the network. Is caching somehow responsible for this? Displaying 12 Images chews up about 10 Megs of memory, which is about 100X filesize.

+1  A: 

I don't see anything obviously wrong; I think more details would be necessary to diagnose the leak.

Ed Ball
+2  A: 

Unless you are doing anything unusual when loading the images (like using homebrewed image loaders or something) then the GC should wipe them out for you when nothing is referencing them anymore.

Are you holding on to references to the data anywhere? Remember that events and event handlers can sometimes "trick" the garbage collector into thinking that an object is still in use:

MyObject obj = new MyObject();
obj.TheEvent += new EventHandler(MyHandler);
obj = null;
// Now you might think that obj is set for collection but it 
// (probably - I don't have access to MS' .NET source code) isn't 
// since we're still listening to events from it.

Not sure if this applies to you, but at least that's were I'd check if I were you.

Also, if you have access to a profiler, such as AQTime or similar, then running your code through it might give you some hints.

You could also try and see if it makes any difference if you load images from disk or from resources embedded into your assembly.

Isak Savo
+4  A: 

How about not using up all that memory in the first place?

(Note: The following paragraph and code are reproduced from this answer.)

Part of the problem is that it is loading the full image in each. You have to use an IValueConverter to open each image in a thumbnail size by setting either the DecodePixelWidth or DecodePixelHeight properties on the BitmapImage. Here's an example I use in one of my projects...

class PathToThumbnailConverter : IValueConverter {
    public int DecodeWidth {
        get;
        set;
    }

    public PathToThumbnailConverter() {
        DecodeWidth = 200;
    }

    public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        var path = value as string;

        if ( !string.IsNullOrEmpty( path ) ) {

            FileInfo info = new FileInfo( path );

            if ( info.Exists && info.Length > 0 ) {
                BitmapImage bi = new BitmapImage();

                bi.BeginInit();
                bi.DecodePixelWidth = DecodeWidth;
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.UriSource = new Uri( info.FullName );
                bi.EndInit();

                return bi;
            }
        }

        return null;
    }

    public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        throw new NotImplementedException();
    }

}

You may also want to consider IsAsync=True in your Binding so that the converter is called on a background thread.

Joel B Fant
Or even better - use the embedded Thumbnail if one exists so you don't even need to read the entire file and resize it...Lookup BitmapFrame.Thumbnail
xyzzer
@xyzzer: Good to know.
Joel B Fant
The problem I saw though is these often come with black or white frames as part of the thumbnail, which does not always look great, I suppose that is why most picture browsers seem to build their own Thumbnail stores.
xyzzer
That, and that way the browser can control the size of the thumbnails.
Joel B Fant