7

I'm facing a memory leak issue. The leak comes from here:

public static BitmapSource BitmapImageFromFile(string filepath)
{
    BitmapImage bi = new BitmapImage();

    bi.BeginInit();
    bi.CacheOption = BitmapCacheOption.OnLoad; //here
    bi.CreateOptions = BitmapCreateOptions.IgnoreImageCache; //and here
    bi.UriSource = new Uri(filepath, UriKind.RelativeOrAbsolute);
    bi.EndInit();

    return bi;
}

I have a ScatterViewItem, which contains an Image, and the source is the BitmapImage of this function.

The actual thing is a lot more complex than this, so I can't simply put an Image into it. I also can't use the default load options, as the image file might be deleted and hence will face some permission issue accessing the file during deletion.

The problem occurs when I close the ScatterViewItem, which in turn closes the Image. However, the cached memory isnt cleared. So after many cycles, the memory consumption is pretty big.

I tried setting image.Source=null during the Unloaded function, but it didn't clear it.

How do I clear the memory correctly during unloading?

copolii
  • 13,331
  • 9
  • 46
  • 76
Darren Ng
  • 323
  • 5
  • 17
  • This might be of use to you [What is the correct way to free memory in C#](http://stackoverflow.com/questions/6066200/what-is-the-correct-way-to-free-memory-in-c-sharp) – Izzy Feb 06 '15 at 11:19
  • 1
    Thanks, but the sad thing is the GC didn't collect it. Calling GC.Collect() directly didn't collect it either. – Darren Ng Feb 06 '15 at 11:25

1 Answers1

9

I found the answer here. Seems like it's a bug in WPF.

I modified the function to include Freeze:

public static BitmapSource BitmapImageFromFile(string filepath)
{
    var bi = new BitmapImage();

    using (var fs = new FileStream(filepath, FileMode.Open))
    {
        bi.BeginInit();                
        bi.StreamSource = fs;                
        bi.CacheOption = BitmapCacheOption.OnLoad;
        bi.EndInit();
    }

    bi.Freeze(); //Important to freeze it, otherwise it will still have minor leaks

    return bi;
}

I also create my own Close function, which will be called before I close the ScatterViewItem:

public void Close()
{
    myImage.Source = null;
    UpdateLayout();
    GC.Collect();
}  

Because myImage is hosted in a ScatterViewItem, GC.Collect() must be called before the parent is closed. Otherwise, it will still linger in memory.

Community
  • 1
  • 1
Darren Ng
  • 323
  • 5
  • 17