WPF Out Of Memory

起因

程序发布后,运行突然奔溃报Out of Memory,查看日志发现如下类似错误(以下堆栈信息来之网络):

System.OutOfMemoryException: Insufficient memory to continue the execution of the program.
   at System.Windows.Media.Composition.DUCE.Channel.SyncFlush()
   at System.Windows.Media.MediaContext.CompleteRender()
   at System.Windows.Interop.HwndTarget.OnResize()
   at System.Windows.Interop.HwndTarget.HandleMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

或是

  at System.Windows.Media.Composition.DUCE.Channel.SyncFlush()
   at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable`1 channelSet)
   at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam)
   at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

问题现象

      这个现象主要发生于XP系统,至少在我自己的一台XP系统发生了,当然最关键的是在领导的XP系统也发生了。

      更不幸的是eventvwr也未招供任何信息,网络搜索结果也是一堆问题,但是都没解决方案,有说是由于WPF的透明度、颜色问题,显卡驱动问题,但都直接被下面的答案否了,人家说根本没用。

      在领导机器发生时,虽然使用visual studio 2010调试,但无任何特殊提示,就突然报了异常。我们把主窗口换成了一个空白的窗口,现象没有发生;尝试着打开dxdiag关掉了硬件加速还是报错,不过重新编译后再运行又正常了,之后再打开硬件加速,不管如何折腾问题都不再重现。当时推断和dxdiag有关,但由于版本发布匆忙,还有多处已知内存泄漏,加之空白窗口没问题,一度怀疑是自己程序问题。

      接着的几天便是没日没夜的对电脑进行摧残,终于黄天不负有心人,在我机器上得到重现,通过一步步排查,发现当程序未使用最大化打开时是正常的,使用最大化模式打开后便报类似错误,使用正常窗体(也就是默认大小)打开点击最大按钮也报错。这时才发现一直冤枉了一张只有40多K的PNG图片(1600*600),因为有没有它现象依旧。

      Dump文件也是没问题,虽然我曾一顿纠结于在没有抓Dump就关闭了硬件加速,但后来发现即使有Dump文件也基本没用。

      由于重现是比较随机的,在“玩弄”了几次之后,我的机器又恢复了正常,但发现以下现象:

1.windows自带的mspaint无法粘贴图片了,报“获取剪切板数据出错”的错误。

2.运行CLIPBRD,发现不能显示图片,且显示如下信息“剪切板查看器无法以当前格式显示信息,或没有足够的内存显示信息,请退出一个或多个应用程序以增加可用内存”。

3.即使mspaint能粘贴图片了图片也是黑底的。

4.物理内存、CPU都比较正常,但CPU多用于内核使用(通过ProcessExplorer)。

问题原因

      内存确实不够,那么是哪个内存导致的结果,虚拟内存,物理内存、显卡内存?还是共同作用的结果。

1.针对性的分别把虚拟内存设置在系统盘,并在100M-200M之间,系统盘磁盘空间小于80M

2.使用C#,通过new Byte,一直来占据内存。

3.使用C#,一直加载一张接近2M的图片,一直来占据显存

       通过实验发现,除了显存一项外其他都不会影响测试结果,通过第三项能有机率还原之前的异常,当然物理内存不够也会报错,只是会随机的在XAML加载时便会报错,而不是本文报的这个错。

解决问题

既然发现了原因,那么如何解决?

告诉客户使用运行打开dxdiag,在显示也中禁用硬件加速,之后重新启动计算机。

那么我们程序能做什么?

1.在程序启动时,判断显存是否足够,当然这需要API支持。intel,N卡,A卡都有自己方法可以使用,具体请自行网络搜索。

2.什么都不做。是的,你没看错,而且这是我们最后定下的解决方案!这得感谢GPU-Z的这款可查看显存使用量的软件,它告诉我们有些显卡是无法查看显存的,而能查看显存的机器似乎都不会报这个错误。我的机器是联想的一体机,显卡型号为Intel(R) G41 Express Chipest,欢迎测试拍砖。

当然我们也想过是否对主窗口的内容进行修减,但这又未尝不是一件好事,启动时就报错总好过业务做了一半再报错。

PS:

这个BUG网上有说是WPF的问题,因为其他程序基本没出现过。

2013-12-17 追加:由于我们的窗体是没有边框的,所以AllowTransparency属性为false,这种几率会降低(降低不是说没有),另外再必现这种问题时,打开Chrome浏览器开N个网页都没问题,怀疑是显卡内存比较碎,而WPF一次分配过大所至,而且发生这种显存问题都是因为feiqiu?每次有问题它都打开,关了就没问题了。

原文地址:https://www.cnblogs.com/Curry/p/3417590.html