15

我有一个自定义方法,可以找到用于给定字符串和字体的最大尺寸来填充给定框而不切断文本。为了测试它,我创建了一个服务,该服务在几个不同的字符串和几个不同的字体之间循环,并在 Parallel.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...

在研究这个问题时,我发现未处理的绘图对象(图形、图标等)是造成这种情况的常见原因,但我找不到任何正在使用的 Disposable 对象。文本大小代码使用 WPF 类(FontFamily、FormattedText 和 Typeface),它们都没有实现 IDisposable。

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

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

4

1 回答 1

1

当 WPF 尝试为另一个新的 Dispatcher 分配本机 Win32 窗口句柄时,似乎引发了异常。也许您已达到流程的最大句柄数量?

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

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

于 2011-07-10T07:33:11.163 回答