Silverlight:从流中创建BitmapImage时抛出异常(灾难性故障(HRESULT异常:0x8000FFFF(E_UNEXPECTED)))

7
我需要动态加载许多(有时数百个)缩略图。出于性能原因,我需要在有限的请求数量内完成此操作,目前为测试,我正在使用单个请求/响应。我在响应中发送图像的二进制数据,并使用MemoryStream将其加载到BitmapImage中。这样做可以正常工作,直到我加载了超过80个缩略图,然后我会收到“灾难性故障”异常。为确保我的数据没有损坏,我尝试使用相同的字节数组多次加载BitmapImage,但是在加载了80次左右后它会崩溃。
以下是从字节数组中加载图像的示例,已知该字节数组具有有效的图像数据(png):
private BitmapImage LoadImage(byte[] imageData)
{
    BitmapImage img = new BitmapImage();
    MemoryStream stream = new MemoryStream(imageData);
    img.SetSource(stream); // Exception thrown here after too many images loaded.
    return img;
}

我随后将BitmapImage用作页面上Image元素的源,但错误发生在上面的img.SetSource(...)行。

在加载缩略图像的循环中添加GC.Collect()可以让我加载更多的图像,所以我认为这与内存管理有关,但我不知道该怎么解决这个问题。


我不确定这是否可能是问题,但MemoryStream确实具有ReadTimeout和WriteTimeout属性。流是否超时? - Danexxtone
我尝试设置ReadTimeout,但是出现了异常:此流不支持超时。 - toby
你能解释一下吗:为什么要使用字节数组?难道不能直接从下载的流中提取数据并将其直接传递给img.SetSource吗?你确定下载的PNG文件是“缩略图”大小,还是正在下载被图像控件缩放的更大的图像?这些缩略图是照片的缩略图吗? - AnthonyWJones
我正在通过单个请求下载多个图像,因此无法直接将请求提供给img.SetSource(因此使用字节数组)。这些图像是全尺寸的,因为我正在为主视图框架缓存它们,但它们是扫描文档,大小不是很大(大多数文件大小在100kb到200kb之间)。如果问题是数据量太大,我会预期出现某种内存不足错误。 - toby
你能展示更多与加载和处理相关的代码吗?还有一些问题,通过查看代码可能会更快地得到答案。 - Danexxtone
2个回答

6
我认为引用微软在以上错误报告中提供的答案是值得的,因为它非常简洁而且描述了问题,并提供了一个推荐的解决方案:
当Silverlight加载图像时,框架会保持对已解码的图像的引用和缓存,直到流控制返回到UI线程调度程序。当您在紧密循环中加载图像时,即使您的应用程序没有保留引用,GC也无法在我们返回流控制时释放该图像,直到我们释放该引用。
处理了大约20个图像后,您可以停止并使用Dispatcher.BeginInvoke排队下一组,以打破在一个批次中处理的工作量。这将允许我们释放应用程序未保留的图像。
我知道当前的解码行为并不明显,Silverlight正在保留这些引用,但更改解码器设计可能会影响其他领域,因此,目前我建议将此类图像分批处理。
现在,如果您实际上要加载500张图像并保留它们,则根据图像大小,仍然有可能耗尽内存。如果您正在处理多页文档,则可能希望在后台按需加载页面,并在超出视图时释放它们,并具有少量页面缓冲区,以便在任何时候都不会超出合理的纹理内存限制。

0

我向微软提交了一个关于这个问题的错误报告:从流中加载太多BitmapImage对象后抛出灾难性失败异常

目前,我将尝试通过使用较小的图像文件来处理缩略图和/或不加载太多的BitmapImages(当它们不在可视区域时卸载图像,并在它们进入视野时重新加载)来解决此问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接