“操作成功完成”例外
我有一个自定义方法,可以找到给定字符串和字体的最大尺寸,以填充给定的框而不切断文本。为了测试它,我创建了一个服务,它循环使用几个不同的字符串和一些不同的字体,并在 Parallel.For 循环中批量执行它们。当此服务运行时,系统上的所有 CPU 核心都处于 %90-%100。运行8、9个小时后,就会开始抛出异常。大多数情况下它仍然可以工作,但偶尔会出现异常或突发异常。
最里面的异常包含消息“操作成功完成”,并且源自 FormattedText 对象上的 WidthInducingTrailingWhitespace 访问器。调用堆栈如下所示:
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 文本渲染的问题?
I have a custom method that finds the largest size to use for a given string and font to fill a given box without cutting off the text. To test it, I created a service that cycles through a few different strings and a few different fonts and does batches of them in a Parallel.For loop. When this service is running, all the CPU cores on a system are at %90-%100. After running for 8 or 9 hours, it will start throwing exceptions. It will still work most of the time, but there will be the occasional exception or burst of exceptions.
The innermost exception has the message "The operation completed successfully" and is originating from the WidthIncludingTrailingWhitespace accessor on a FormattedText object. The call stack looks like this:
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...
In researching this, I found that undisposed drawing objects (Graphics, Icons, etc) are a common cause for this, but I could not find any Disposable objects in use. The text sizing code uses WPF classes (FontFamily, FormattedText, and Typeface) and none of them implement IDisposable.
I have perfmon monitoring the process and while memory use, handle count, and thread count do vary quite a bit, they never skyrocket out of control. This tells me it probably isn't a handle leak. What else could it be?
UPDATE: I have been running the test for a few days now with one significant change: it is doing a regular for instead of a parallel for. It hasn't crashed yet and perfmon shows horizontal lines with very little variance. Perhaps this is an issue with parallelization and not WPF text rendering?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当 WPF 尝试为另一个新的调度程序分配本机 Win32 窗口句柄时,似乎引发了异常。也许您已达到进程的最大句柄数?
您是否尝试在每次迭代时强制进行垃圾收集?大多数 WPF 类不实现 IDisposable,但它们仍然使用非托管资源,这些资源在 WPF 内部进行管理。
我可以想象还有另一种溢出方式。 CurrentDispatcher 属性为每个线程创建一个新的 Dispatcher。每个 Dispatcher 都不会停止,直到调用 InvokeShutdown 为止。所以这意味着Dispatcher工作的线程永远不会被终止,因为没有Window,也没有人按下关闭按钮。也许它会强制 Parallel.For 实现为下一次迭代分配一个新线程,这还需要另一个新的 Dispatcher 和另一个新句柄。不幸的是,我没有太多使用并行的经验,所以这只是假设。
It looks like exception was raised when WPF tried to allocate native Win32 window handle for another new Dispatcher. Maybe you have reached the maximum amount of handles for your process?
Did you try to force garbage collection on each iteration? The most WPF classes doesn't implement IDisposable, but they still use unmanaged resources, which are managed inside WPF.
There is another way for overflow I can imagine. The CurrentDispatcher property creates a new Dispatcher for each thread. Every Dispatcher never stop until InvokeShutdown will be called. So it means that a thread where a Dispatcher works will never be terminated, because there is no Window and there is nobody to press the Close button. Perhaps it forces Parallel.For implementation to allocate a new Thread for a next iteration, which also need another new Dispatcher and another new handle. Unfortunately, I don't have much experience in using Parallel, so this is only supposition.