Wpf &引用;“操作已成功完成”;例外

Wpf &引用;“操作已成功完成”;例外,wpf,exception,windows-services,hwnd,Wpf,Exception,Windows Services,Hwnd,我有一个自定义方法,可以找到给定字符串和字体的最大大小,以填充给定的框,而不切断文本。为了测试它,我创建了一个服务,该服务循环使用几个不同的字符串和几个不同的字体,并在并行的.For循环中对它们进行批处理。当此服务运行时,系统上的所有CPU核心都处于%90-%100。在运行8或9小时后,它将开始抛出异常。它大部分时间仍然有效,但偶尔会出现异常或突发异常 最里面的异常包含消息“操作已成功完成”,它来自FormattedText对象上的WidthIncludingTrailingWhitespace

我有一个自定义方法,可以找到给定字符串和字体的最大大小,以填充给定的框,而不切断文本。为了测试它,我创建了一个服务,该服务循环使用几个不同的字符串和几个不同的字体,并在并行的.For循环中对它们进行批处理。当此服务运行时,系统上的所有CPU核心都处于%90-%100。在运行8或9小时后,它将开始抛出异常。它大部分时间仍然有效,但偶尔会出现异常或突发异常

最里面的异常包含消息“操作已成功完成”,它来自FormattedText对象上的WidthIncludingTrailingWhitespace访问器。调用堆栈如下所示:

   at MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D wc_d)
   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.Dispatcher.get_CurrentDispatcher()
   at System.Windows.Media.TextFormatting.TextFormatter.FromCurrentDispatcher(TextFormattingMode textFormattingMode)
   at System.Windows.Media.FormattedText.LineEnumerator..ctor(FormattedText text)
   at System.Windows.Media.FormattedText.DrawAndCalculateMetrics(DrawingContext dc, Point drawingOffset, Boolean getBlackBoxMetrics)
   at System.Windows.Media.FormattedText.get_Metrics()
   at System.Windows.Media.FormattedText.get_WidthIncludingTrailingWhitespace()
   ...My Library Here...
在研究这一点时,我发现未经处理的绘图对象(图形、图标等)是造成这种情况的常见原因,但我找不到任何使用中的一次性对象。文本大小调整代码使用WPF类(FontFamily、FormattedText和Typeface),它们都没有实现IDisposable

我有perfmon监控进程,虽然内存使用、句柄计数和线程计数确实有很大差异,但它们从未失控。这告诉我这可能不是把手泄漏。还可能是什么


更新:我已经运行了几天的测试,现在有一个重大的变化:它是做一个常规的for,而不是并行的for。它还没有崩溃,perfmon显示的水平线变化很小。也许这是并行化的问题,而不是WPF文本呈现的问题?

当WPF试图为另一个新的调度程序分配本机Win32窗口句柄时,似乎出现了异常。可能您已经达到了进程的最大句柄数

您是否尝试在每次迭代中强制垃圾收集?大多数WPF类没有实现IDisposable,但它们仍然使用非托管资源,这些资源在WPF内部进行管理


我可以想象,还有另一种溢出方式。CurrentDispatcher属性为每个线程创建一个新的调度程序。在调用InvokeShutdown之前,每个调度程序都不会停止。这意味着分派器工作的线程永远不会终止,因为没有窗口,也没有人按下关闭按钮。也许它会强制Parallel.For实现为下一次迭代分配一个新线程,这也需要另一个新的调度程序和另一个新句柄。不幸的是,我在使用Parallel方面没有太多经验,所以这只是一个假设。

我在进程上运行perfmon,句柄使用率上下波动很多-它没有上升趋势,所以我认为这不是问题所在。我尝试过定期强制垃圾收集,但没有效果。最后一个建议很有趣。Perfmon在线程方面没有显示任何上升趋势,但这是一个很好的线索。谢谢