Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
670 views
in Technique[技术] by (71.8m points)

c# - How to dispose BitmapImage cache?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...