System.Drawing.Bitmap中的C#OutOfMemoryException
有没有办法在运行时获得有关OutOfMemoryException的更多详细信息?或者,这个异常是否可以不被包含的try/catch捕获,而是被调用堆栈上更高的try/catch捕获?我无法使用WinDBG进行复制,因此它必须是我可以从应用程序中记录的内容 我为冗长的解释道歉,但是有很多可能的原因需要消除,我解释了 我已经阅读了OutofMemoryException的所有可能性,并基本上消除了所有这些可能性。通常,应用程序运行得很好,但偶尔在某些计算机上,我会遇到OutOfMemoryException。由于这些报告在现场无法在本地复制,因此我只有日志可供参考。但我有相当多的细节 奇怪的是:System.Drawing.Bitmap中的C#OutOfMemoryException,c#,.net,out-of-memory,.net-4.5,C#,.net,Out Of Memory,.net 4.5,有没有办法在运行时获得有关OutOfMemoryException的更多详细信息?或者,这个异常是否可以不被包含的try/catch捕获,而是被调用堆栈上更高的try/catch捕获?我无法使用WinDBG进行复制,因此它必须是我可以从应用程序中记录的内容 我为冗长的解释道歉,但是有很多可能的原因需要消除,我解释了 我已经阅读了OutofMemoryException的所有可能性,并基本上消除了所有这些可能性。通常,应用程序运行得很好,但偶尔在某些计算机上,我会遇到OutOfMemoryExce
- 任何逻辑上可能在附近分配内存的内容都在try/catch中,但异常被视为未处理(并且在调用堆栈的更高层被捕获)
- 没有正在使用的StringBuffers
- 即使在重新启动并重新启动应用程序后,也会发生异常
- 异常仅在几分钟后发生,并且仅分配了大约30MB的内存,内存块不超过1.5MiB
- 已验证应用程序(为“任意”处理器构建)是否以64位运行
- 不缺少磁盘空间(270Gb可用空间)并且启用了pagefile
- 似乎不是一个可能的LoH碎片问题
- 它发生在线程池线程中(System.Timers.Timer,[Statthread])
- 少量活动线程(<5个)
- 它发生在下载1MiB文件时。它被读入一个内存流,所以它可以大到2MB。然后将其馈送到System.Drawing.Bitmap构造函数,生成大约8MB的位图。但是,这一切都在捕获System.Exception的try/catch中完成。try/catch中唯一没有的是返回byte[]引用,它应该只是一个引用副本,而不是任何内存分配
- 在此之前,没有进行过其他重要的内存分配。在我的本地版本中查看heap(应该以相同的方式运行),只会显示应用程序图标和几十个小对象堆上的对象
- 它可以在具有特定输入的特定系统上重复。然而,这些系统是相互克隆的。唯一明显的变化是windows更新的顺序
- 我正在运行的程序集已签名。难道没有一个校验和来确保它不被破坏吗?所有系统组件是否相同?我看不出这个实例是如何被损坏的DLL甚至数据解释的
- 在发生异常时查看调用堆栈出人意料地毫无帮助。我在下面的代码中指出抛出异常的位置
- COM对象有一些用途。然而,在正常情况下,我们会在没有内存问题的情况下运行应用程序数周,当我们遇到这些异常时,它们几乎是立即出现的,只使用了大约20个相对轻量级的COM对象(IUPnPDevice)
还有..是否有任何原因导致OutOfMemoryException不会被第一次try/catch捕获,而是在调用堆栈的更高层被捕获?谢谢大家。答案有点奇怪,我把一些细节搞错了,很难弄清楚。错误在这里:
Bitmap bmp;
using (var ms = new MemoryStream(data))
{
bmp = new Bitmap(ms);
}
bitmap = bmp;
在位图构造函数文档中的备注中,我发现:
您必须在位图的生存期内保持流打开
显然,在构建之后立即关闭MemoryStream违反了这一点。在这段时间和我实际使用位图的时间之间进行的垃圾收集显然造成了错误。(编辑:实际上,在1MiB左右似乎存在一个边界,其中FromStream函数最初只会解压缩JPEG文件的这么多。对于JPEG<1MiB的图像,整个图像被解压缩,并且在初始化后实际上不使用流。对于较大的JPEG,在需要这些像素之前,它不会读取超过前1MiB的图像)
我很难想象微软为什么会这样做。我也不想让原始流保持打开状态(这是一个http连接),因此我看到的唯一解决方案是克隆位图:
// Create a Bitmap object from a file.
using (var ms = new MemoryStream(data))
{
bmp = new Bitmap(ms);
Rectangle cloneRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.PixelFormat format = bmp.PixelFormat;
this.bitmap = bmp.Clone(cloneRect, bmp.PixelFormat);
}
导致我长期沮丧的搜索和排除一条关键信息的原因是,在客户机上执行的代码是一个稍旧的版本,只有一个细微的更改。Graphics.FromImage()在以前的版本中被调用于位图,但已被删除。尽管如此,该版本在绝大多数情况下运行良好。由于字节数组(数据),可以预期内存会出现碎片。让DownloadBinaryFile返回一个流。您可以根据数据大小选择返回MemoryStream或FileStream。您可以向我们展示stacktrace吗?这可能是由碎片引起的,有关可能的解决方法,请参阅。你也可以用它来帮助你进行调试
// Create a Bitmap object from a file.
using (var ms = new MemoryStream(data))
{
bmp = new Bitmap(ms);
Rectangle cloneRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.PixelFormat format = bmp.PixelFormat;
this.bitmap = bmp.Clone(cloneRect, bmp.PixelFormat);
}