您如何确保 WPF 从内存中释放大型 BitmapSource? [英] How do you make sure WPF releases large BitmapSource from Memory?

查看:32
本文介绍了您如何确保 WPF 从内存中释放大型 BitmapSource?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

系统:Windows XP SP3,.NET 3.5,4GB RAM,双 1.6GHz

System: Windows XP SP3, .NET 3.5, 4GB RAM, Dual 1.6gHz

我有一个 WPF 应用程序,可以加载和转换(使用故事板动画)极大的 PNG.这些 PNG 的分辨率为 8190x1080.当应用程序运行时,它似乎会缓存图像,系统内存会慢慢增加.最终它使系统窒息并抛出 OutOfMemoryException.

I have a WPF application that loads and transitions (using Storyboard animations) extremely large PNGs. These PNGs are 8190x1080 in resolution. As the application runs it appears to cache the images and the system Memory slowly creeps up. Eventually it chokes the system and throws the OutOfMemoryException.

以下是我目前正在尝试解决此问题的步骤:

Here are the steps I am currently taking to try to solve this:

1)我正在从应用程序中删除 BitmapSource 对象

1)I am removing the BitmapSource objects from the app

2) 我在加载 BitmapSource 时将 BitmapSource BitmapCacheOption 设置为 None

2)I am setting the BitmapSource BitmapCacheOption to None when I load the BitmapSource

3) BitmapSource 加载后我将其冻结.

3)I am Freezing the BitmapSource once it's loaded.

4) 我将删除对使用源的图像的所有引用以及对源本身的任何引用.

4)I am deleting all references to the Image that uses the source as well as any references to the source itself.

5)以上步骤完成后手动调用GC.Collect().

5)Manually calling GC.Collect() after above steps have completed.

希望弄清楚为什么 WPF 会挂在这些图像的内存上,以及确保正确恢复用于加载它们的内存的可能解决方案.

Hoping to figure out why WPF is hanging onto memory for these images and a possible solution to ensure that the memory used to load them is properly recovered.

推荐答案

您当然为此付出了很多努力.我认为主要问题是 BitmapCacheOption.None 不会阻止底层 BitmapDecoder(s) 被缓存.

You certainly have put in a lot of work on this. I think the main problem is that BitmapCacheOption.None doesn't prevent the underlying BitmapDecoder(s) from being cached.

对此有几个棘手的解决方案,例如执行 GC.Collect()、从 300 个不同的 Uris 加载 300 个小图像,然后再次调用 GC.Collect(),但简单的一个很简单:

There are several tricky solutions to this such as doing a GC.Collect(), loading 300 small images from 300 different Uris, and calling GC.Collect() again, but the simple one is straightforward:

不是从 Uri 加载,只需构造一个 Stream 并将其传递给 BitmapFrame 的构造函数:

Instead of loading from a Uri, just construct a Stream and pass it to BitmapFrame's constructor:

var source = new BitmapImage();
using(Stream stream = ...)
{
  source.BeginInit();
  source.StreamSource = stream;
  source.CacheOption = BitmapCacheOption.OnLoad;    // not a mistake - see below
  source.EndInit();
}

这应该起作用的原因是从流加载会完全禁用缓存.不仅顶级源没有缓存,内部解码器也没有缓存.

The reason this should work is that loading from a stream completely disables the cache. Not only is the top-level source not cached, but none of the internal decoders are cached either.

为什么是 BitmapCacheOption.OnLoad?这似乎违反直觉,但该标志有两个作用:如果可以缓存,则启用缓存,并导致加载发生在 EndInit() 处.在我们的例子中缓存是不可能的,所以它所做的一切都会导致加载立即发生.

Why BitmapCacheOption.OnLoad? It seems counterintuitive, but this flag has two effects: It enables caching if caching is possible, and it causes the load to happen at EndInit(). In our case caching is impossible, so all it does it cause the load to happen immediately.

显然,您需要在 UI 线程之外运行此代码,然后冻结 BitmapSource 以便您可以将其移动.

Obviously you'll want to run this code off your UI thread, then freeze the BitmapSource so you can move it over.

您可能还想知道为什么我没有使用 BitmapCreateOptions.IgnoreImageCache.除了在没有给定 URI 的情况下缓存是不可能的这一事实之外,IgnoreImageCache 并没有完全忽略图像缓存:它只是在读取时忽略它.所以即使设置了 IgnoreImageCache,加载的图片仍然会被插入到缓存中.不同之处在于缓存中的现有图像会被忽略.

You may also wonder why I didn't use BitmapCreateOptions.IgnoreImageCache. Other than the fact that caching is impossible any with no URI given, the IgnoreImageCache doesn't completely ignore the image cache: It only ignores it for reading. So even if IgnoreImageCache is set, the loaded image is still inserted into the cache. The difference is that the existing image in the cache is ignored.

这篇关于您如何确保 WPF 从内存中释放大型 BitmapSource?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆