我有一个应用程序,它从XML文件(到字节数组)读取JPEG,生成MemoryStreams并使用它们来实例化BitmapImages。 JPEG的整个大小约为60 MB。但是,我的应用程序的内存使用量为1.6GB(之后会出现系统内存不足的情况)。
我在内存中保留了字节数组,MemoryStreams和(当然)BitmapImages。因此,我希望将原始大小存储在内存中大约三倍(可能更多),但1.6GB是荒谬的。
可能导致这种情况的原因是什么?
提前感谢您的帮助。
答案 0 :(得分:2)
真的不是那么荒谬。要记住的一个好的经验法则是,平均而言,JPEG大约是保存为BMP的同一图像大小的10%。有些图像更易于压缩,有些图像更少,JPEG编码器的质量和压缩设置会产生显着差异,但根据我的经验,这个原则通常都有。
如果我们在这种情况下接受规则为true,那么您的程序仅存储至少720MB的图像数据;字节数组中的60MB JPEG数据再次存储在MemoryStream中,然后是600MB未压缩的BMP图像。此外,程序还将自身和任何引用的第三方二进制文件加载到同一个内存空间(包括引用的Framework命名空间的DLL;人们常常忘记框架不是“免费”使用,因为它是“内置的” ),并记住某些集合以非常乐观的方式为自己请求记忆;例如,每次达到List的内部最大容量时,它会自行调整大小以使其先前的大小加倍。字典也是如此,增加了维护两个内部数组结构的开销。一个用于键哈希,另一个用于“节点”,包含链接到键哈希的实际值。此行为很容易导致处理大量对象集合的程序请求比允许运行时提供的内存更多的内存。然后,如果这是一个图形应用程序,运行时为每个使用图形元素的线程维护一个消息循环,并挂钩到每个图形元素(每个“窗口”,尽管该术语是用词不当,因为几乎所有的GUI元素都是“ windows“,而不仅仅是你通常称之为窗口的Form对象。”
所有这些都可以轻松地使应用程序需要1.6GB的托管内存。然后,当应用程序要求400MB以上的内存(以调整大型集合的大小),或者要求超过21亿的新句柄时(即使在64位操作系统中,.NET也使用32位索引,因此运行时只能跟踪每个进程总共2个 32 不同的内存地址),运行时将注入一个OOME。