3

I'm creating a Windows phone application that shows a list of thumbnails. I'm using a LongListSelector to do it.

My application has memory leaks when I navigate forward and backward to the thumbnails list some times. I review the memory usage while using the App and I see that the memory increases when opening the page with the thumbnails (as I expect to). When I navigate back to the previous page the memory usage decrease but not as much at it was increased. Repeating the proces several times it ends in an out of memory exception.

I created a test application that only has two pages. One with a button to navigate to other that loads a set of potos in a LongListSelector. I create this App to be sure that the memory leak is not caused by something else.

In this simple test the memory usage behaves as it does in my App.

Here is the main code of my page with the thumbnais:

public class testObject
{
    public string Title { get; set; }
    public BitmapImage Thumbnail { get; set; }
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{

    photosList = new List<testObject>();
    for (int i = 0; i < 200; i++)
    {
        BitmapImage bi = new BitmapImage(new Uri("/images/"
                                        + i.ToString()+".jpg",
                                        UriKind.RelativeOrAbsolute));


        photosList.Add(new testObject { Title = i.ToString(),
                                            Thumbnail = bi });
    }

    GridPictures.ItemsSource = photosList;

}

protected override void OnBackKeyPress(
            System.ComponentModel.CancelEventArgs e)
{
    foreach (testObject test in photosList)
    {
        test.Thumbnail.DecodePixelHeight = 1;
        test.Thumbnail.DecodePixelWidth = 1;
        test.Thumbnail = null;
    }
    photosList.Clear();
    photosList = null;

    base.OnBackKeyPress(e);
}

And here is the code of the button on the other page:

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    NavigationService.Navigate(new Uri("/Page1.xaml", UriKind.RelativeOrAbsolute));

}
crm27
  • 73
  • 9

1 Answers1

2

LongListSelector is a known source of leaks. Those leaks become especially troublesome when you're using controls like Image, which uses a large amount of memory.

The best solution, so far, is to avoid LongListSelector altogether. But it you can't find a suitable alternative, you have a few workarounds:

  • In Page1, in the OnNavigatedFrom event, force the liberation of the pictures. There's a few ways to do that, but usually setting the ImageSource property to null is enough

  • Make a custom control to do the dirty work for you

The custom control could look like:

public class SafePicture : System.Windows.Controls.ContentControl
{
    public SafePicture()
    {
        this.Unloaded += this.SafePictureUnloaded;
    }

    private void SafePictureUnloaded(object sender, System.Windows.RoutedEventArgs e)
    {
        var image = this.Content as System.Windows.Controls.Image;

        if (image != null)
        {
            image.Source = null;
        }
    }
}

Then, just wrap all your pictures in that control:

<my:SafePicture>
    <Image Source="{Binding Path=Thumbnail}" />
</my:SafePicture>

And that should do the trick. Note that you will still be leaking memory, but in far more reasonable amounts.

Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94