Исключение «Операция завершена успешно» - PullRequest
15 голосов
/ 08 июля 2011

У меня есть собственный метод, который находит наибольший размер для данной строки и шрифта, чтобы заполнить данное поле, не обрезая текст. Чтобы проверить это, я создал сервис, который циклически перебирает несколько разных строк и несколько разных шрифтов и выполняет их пакетирование в цикле Parallel.For. Когда эта служба работает, все ядра ЦП в системе находятся на% 90-% 100. После запуска в течение 8 или 9 часов, он начнет выдавать исключения. Это все еще будет работать большую часть времени, но будут случайные исключения или серии исключений.

Самое внутреннее исключение имеет сообщение «Операция успешно завершена» и исходит из метода доступа WidthInclusiveTrailingWhitespace объекта FormattedText. Стек вызовов выглядит так:

   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, наблюдающий за процессом, и хотя использование памяти, количество обработчиков и количество потоков сильно различаются, они никогда не выходят из-под контроля. Это говорит мне, что это, вероятно, не утечка ручки. Что еще это может быть?

ОБНОВЛЕНИЕ: я проводил тест в течение нескольких дней с одним существенным изменением: он выполняет регулярное выполнение вместо параллельного для. Он еще не разбился, и perfmon показывает горизонтальные линии с очень небольшим отклонением. Возможно, это проблема параллелизации, а не рендеринга текста WPF?

1 Ответ

1 голос
/ 10 июля 2011

Похоже, исключение возникло, когда WPF попытался выделить собственный дескриптор окна Win32 для другого нового Диспетчера. Может быть, вы достигли максимального количества дескрипторов для вашего процесса?

Вы пытались форсировать сборку мусора на каждой итерации? Большинство классов WPF не реализуют IDisposable, но они по-прежнему используют неуправляемые ресурсы, которые управляются внутри WPF.

Есть другой способ переполнения, который я могу себе представить. Свойство CurrentDispatcher создает новый Dispatcher для каждого потока. Каждый Диспетчер никогда не останавливается, пока не будет вызван InvokeShutdown. Таким образом, это означает, что поток, в котором работает Dispatcher, никогда не будет прерван, потому что нет окна и некому нажимать кнопку «Закрыть». Возможно, это заставляет реализацию Parallel.For выделить новый поток для следующей итерации, для которой также потребуется еще один новый диспетчер и еще один новый дескриптор. К сожалению, у меня нет большого опыта использования Parallel, так что это только предположение.

...