【发布时间】:2015-12-21 10:46:51
【问题描述】:
我遇到了一个我无法解决的问题,也无法在任何地方使用谷歌解决方案。
我正在运行加载或保存图像并使用BitmapEncoder 或BitmapDecoder 类的服务。一段时间后(取决于我保存/加载图像的频率)服务拒绝保存/加载图像。首先,我在事件日志中看到警告
堆分配失败
我用谷歌搜索了它是什么意思,它与 Windows 服务拥有的有限数量的 GDI 对象有关。可以修改注册表以增加这些对象的数量,但我认为这不是很好的解决方案,而且对我也不起作用。
我的代码在保存时抛出以下异常并带有堆栈跟踪
Error while storing image : System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
at System.Windows.Threading.Dispatcher..ctor()
at System.Windows.Threading.DispatcherObject..ctor()
at System.Windows.Media.Imaging.BitmapEncoder..ctor(Boolean isBuiltIn)
at Imaging.TiffReadWrite.Save(String filename, Image img)
加载时
Error while loading image : System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
at System.Windows.Threading.Dispatcher..ctor()
at System.Windows.Threading.DispatcherObject..ctor()
at System.Windows.Media.Imaging.BitmapDecoder..ctor(Stream bitmapStream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, Guid expectedClsId)
at Imaging.TiffReadWrite.Load(String filename)
我保存图片的代码如下:
public static void Save(string filename, BitmapSource img)
{
using (FileStream stream = new FileStream(filename, FileMode.Create))
{
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.None;
BitmapFrame frm = BitmapFrame.Create(img);
encoder.Frames.Add(frm);
encoder.Save(stream);
}
}
加载图片的方式如下:
public static BitmapSource Load(string filename)
{
BitmapSource resultImage = null;
using (Stream imSource = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var decoder = new TiffBitmapDecoder(imSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
resultImage = decoder.Frames[0];
}
return resultImage;
}
因此,服务拒绝保存/加载图像。我可以尝试/捕获此异常,以便服务可以继续运行,但无法保存/加载图像。有时在第一次发生此异常后,可能会保存/加载很少的图像,并且在一段时间后不会执行保存/加载。
我唯一解决此问题的方法不是在服务中运行此代码,而是在应用程序中运行。然后它运行得很好,但这不是我正在寻找的解决方案。如果有人有更好的建议,请告诉我。
有一些类似的帖子(异常的堆栈跟踪或多或少相同)实际上并没有解决:
【问题讨论】:
-
嗯,这是一个非常无用的异常消息。服务在会话 0 中运行,它有一个故意小的桌面堆。这使得 CreateWindowEx() 更有可能失败。顺便说一句,可能是另一项服务占据了不公平的份额。或者您的,任务管理器中的“用户对象”计数器是您的第一个诊断。您还冒着没有足够频繁地收集 GC 的风险,您可能需要通过每 N 个位图自己调用 GC.Collect() 来提供帮助。然而,没有有意义的错误代码这一事实确实表明存在环境问题。
-
感谢您的回复。我知道它含糊不清,这就是为什么我无法解决它。我检查了任务管理器并使用 dheapmon 跟踪 GDI 对象,我只发现 WinLogon 的使用率很高,但仅此而已。它可能是另一种服务,但在使用我发布的代码的不同服务的不同 PC 上观察到。所以可能性不大。我想我已经有足够多的 GC.Collect() 调用了。所以这也无济于事。
-
@TomKos,考虑使用
BitmapCacheOption.None值作为TiffBitmapDecoder类的构造函数参数和BitmapFrame.Create()方法调用的参数。 -
WPF 不使用 GDI。但这可能与线程模型有关。您的代码是否在 STA 线程中运行?能否分享更多代码以便我们重现(PS:服务器代码不支持 WPF)?
-
我知道它不容易重现,因为它会在一段时间(几小时,几天)后发生。但除此之外,您所需要的一切。只需创建一个循环,您将在其中保存/加载图像(最好是 >100MB 的大图像)并在 Windows 服务中执行。