Изменить 26 сентября
См. ниже полный фон. tl; dr: Управление сетью данных вызывает нечетные исключения, и я ищу помощь, чтобы изолировать причину и найти решение.
Я сузил это немного дальше. Я смог воспроизвести поведение в более маленьком тестовом приложении с более надежным запуском ошибочного поведения.
Я могу определенно исключить проблемы с потоками и (я думаю). Новое приложение не использует никаких задач или других потоков/асинхронных функций, и я могу вызвать необработанное исключение, просто добавив свойства, возвращающие константу в класс объектов, показанных в DataGrid. Это указывает на то, что проблема заключается либо в неуправляемом исчерпании ресурсов, либо в том, о чем я еще не думал.
Пересмотренная программа структурирована следующим образом. Я создал пользовательский элемент управления EntityCollectionGridView
, который имеет метку и сетку данных. В элементе управления Loaded event я назначаю List<TestClass>
сетке данных с 1000 или 10000 строк, позволяя сетке генерировать столбцы. Этот пользовательский элемент управления создается в 2-4 раза в MainPage.xaml на странице OnNavigatedTo
event (или Loaded
, это, похоже, не имеет значения). Если возникает исключение, это происходит сразу же после отображения MainPage.
Интересно, что поведение, похоже, не меняется в зависимости от количества отображаемых строк (он будет надежно работать со 10000 строками или надежно с 1000 строк в каждой сетке), а скорее с общим количеством столбцов в все сетки, загруженные в данный момент времени. С 20 свойствами, чтобы показать, 4 сетки прекрасно работают. С 35 свойствами и 4 сетками исключение исключается. Но если я устраню две сетки, тот же класс с 35 свойствами будет работать нормально.
Обратите внимание, что все свойства, которые я добавляю в TestClass
для перехода от 20 до 35 столбцов, имеют форму:
public string StringXYZ { get { return "asdfasdfasdfasdfasf"; } }
Итак, в резервных данных нет дополнительной памяти (и, опять же, я не думаю, что проблема с памятью является проблемой).
Что вы все думаете? Опять же, дескрипторы/пользовательские объекты /etc в диспетчере задач выглядят хорошо, но есть ли что-то еще, что я могу потерять?
Оригинальное сообщение
Я работал над портом DataLink Silverlight Toolkit для WinRT, и он достаточно хорошо прошел в простых тестах (различные конфигурации и до 10000 строк). Однако, поскольку я попытался внедрить его в другое приложение WinRT, я столкнулся с спорадическим исключением (типа System.Exception, поднятым в обработчике App.UnhandledException), что очень сложно отлаживать.
Not enough quota is available to process this command. (Exception from HRESULT: 0x80070718)
Ошибка постоянно воспроизводима, но не детерминистична. То есть я могу сделать это каждый раз, когда я запускаю приложение, но это не всегда происходит, выполняя одинаковый точный набор шагов столько же раз. Вероятно, ошибка возникает при переходе страницы (будь то переход на новую страницу вперед или назад на предыдущую страницу), а не (например) при изменении ItemsSource в datagrid.
Структура приложения - это в основном рекурсивный доступ через иерархию со страницей, отображаемой на каждом уровне иерархии. На странице текущего node в иерархии показаны каждый дочерний элемент node и некоторые узлы внуков, а для любого поднода может отображаться дататайд. На практике я последовательно воспроизвожу это со следующей структурой навигации:
Root page: shows no datagrid
Child page: shows one datagrid and a few listviews
Grandchild page: shows two datagrids, one bound to the
same source as Child page, the other one empty
Типичный тестовый сценарий: начинайте с Root, переходите к Child, переходите к Grandchild, переходите к Child, а затем, когда я пытаюсь снова перейти к Grandchild, он не срабатывает с исключением, о котором я упоминал выше. Но это может быть неудачно в первый раз, когда я удалю внука, или он может позволить мне двигаться назад и вперед несколько раз, прежде чем потерпеть неудачу.
В стеке вызовов есть только один управляемый кадр, который является обработчиком событий необработанного исключения. Это очень бесполезно. Переходя к отладке смешанного режима, я получаю следующее:
WinRTClient.exe!WinRTClient.App.InitializeComponent.AnonymousMethod__14(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) Line 50 + 0x20 bytes C#
[Native to Managed Transition]
Windows.UI.Xaml.dll!DirectUI::CFTMEventSource<Windows::UI::Xaml::IUnhandledExceptionEventHandler,Windows::UI::Xaml::IApplication,Windows::UI::Xaml::IUnhandledExceptionEventArgs>::Raise(Windows::UI::Xaml::IApplication * pSource, Windows::UI::Xaml::IUnhandledExceptionEventArgs * pArgs) Line 327 C++
Windows.UI.Xaml.dll!DirectUI::Application::RaiseUnhandledExceptionEventHelper(long hrEncountered, unsigned short * pszErrorMessage, unsigned int * pfIsHandled) Line 920 + 0xa bytes C++
Windows.UI.Xaml.dll!DirectUI::ErrorHelper::CallAUHandler(unsigned int errorCode, unsigned int * pfIsHandled, wchar_t * * pbstrErrorMessage) Line 39 + 0x14 bytes C++
Windows.UI.Xaml.dll!DirectUI::ErrorHelper::ProcessUnhandledErrorForUserCode(long error) Line 82 + 0x10 bytes C++
Windows.UI.Xaml.dll!AgCoreCallbacks::CallAUHandler(unsigned int errorCode) Line 1104 + 0x8 bytes C++
Windows.UI.Xaml.dll!CCoreServices::ReportUnhandledError(long errorXR) Line 6582 C++
Windows.UI.Xaml.dll!CXcpDispatcher::Tick() Line 1126 + 0xb bytes C++
Windows.UI.Xaml.dll!CXcpDispatcher::OnReentrancyProtectedWindowMessage(HWND__ * hwnd, unsigned int msg, unsigned int wParam, long lParam) Line 653 C++
Windows.UI.Xaml.dll!CXcpDispatcher::WindowProc(HWND__ * hwnd, unsigned int msg, unsigned int wParam, long lParam) Line 401 + 0x24 bytes C++
[email protected]() + 0x23 bytes
[email protected]() + 0xbd bytes
[email protected]() + 0xf8 bytes
[email protected]() + 0x10 bytes
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessMessage(int bDrainQueue, int * pbAnyMessages) Line 121 C++
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessEvents(Windows::UI::Core::CoreProcessEventsOption options) Line 184 + 0x10 bytes C++
Windows.UI.Xaml.dll!CJupiterWindow::RunCoreWindowMessageLoop() Line 416 + 0xb bytes C++
Windows.UI.Xaml.dll!CJupiterControl::RunMessageLoop() Line 714 + 0x5 bytes C++
Windows.UI.Xaml.dll!DirectUI::DXamlCore::RunMessageLoop() Line 2539 + 0x5 bytes C++
Windows.UI.Xaml.dll!DirectUI::FrameworkView::Run() Line 91 C++
twinapi.dll!`Windows::ApplicationModel::Core::CoreApplicationViewAgileContainer::RuntimeClassInitialize'::`55'::<lambda_A2234BA2CCD64E2C>::operator()(void * pv) Line 560 C++
twinapi.dll!`Windows::ApplicationModel::Core::CoreApplicationViewAgileContainer::RuntimeClassInitialize'::`55'::<lambda_A2234BA2CCD64E2C>::<helper_func>(void * pv) Line 613 + 0xe bytes C++
[email protected]() + 0xceab bytes
[email protected]@12() + 0xe bytes
[email protected]() + 0x27 bytes
[email protected]() + 0x1b bytes
Это указывает мне, что все, что я делаю неправильно, не регистрируется до тех пор, пока по крайней мере один цикл в цикле сообщений приложения (и я также попытался взломать все выброшенные исключения, используя "Debug | Exceptions..." - насколько я могу судить, ничего не бросают и не проглатывают). Интересные кадры стека, которые я вижу, это WindowProc
, OnReentrancyProtectedWindowMessage
и Tick
. msg
равен 0x402 (1026), что для меня ничего не значит. Эта страница содержит это сообщение, которое используется в следующих контекстах:
CBEM_SETIMAGELIST
DDM_CLOSE
DM_REPOSITION
HKM_GETHOTKEY
PBM_SETPOS
RB_DELETEBAND
SB_GETTEXTA
TB_CHECKBUTTON
TBM_GETRANGEMAX
WM_PSD_MINMARGINRECT
... но это ничего не значит для меня ни (это может быть даже не актуально).
Три теории, которые я могу придумать, таковы:
- Давление в памяти.Но я столкнулся с этим, при этом 24% свободной физической памяти и приложение потребляют менее 100 МБ памяти. В другое время приложение не будет испытывать каких-либо проблем, перемещаясь через некоторое время и загружая 400 МБ памяти.
- Проблемы с потоками,, такие как доступ к потоку пользовательского интерфейса из рабочего потока. И, фактически, у меня есть доступ к данным, происходящим в фоновом потоке. Но это использует (портированные) рамки, которые были очень надежны в среде WinForms и в плагине Outlook, и я думаю, что использование потоков безопасно. Кроме того, я могу использовать одни и те же данные в этом приложении без каких-либо проблем с привязкой только к ListViews и т.д. Наконец, Grandchild node сконфигурирован таким образом, что выбор строки в первом datagrid запускает запрос для элементов детализации строки, которые отображаются во втором datagrid (который изначально пуст и может оставаться таким, чтобы не предотвратить исключение), Это происходит без перехода на страницу и работает безупречно, пока я предпочитаю играть с выбором. Но переход обратно к Ребенку может сразу меня убить, хотя в этот момент не должно быть доступа к данным и, следовательно, не выполняются операции потоковой передачи, о которых я знаю.
- Исчерпывание ресурсов, возможно, GUI-дескрипторы. Но я не думаю, что я оказываю такое давление на эту систему. В одном выполнении, разбивая обработчик исключений, диспетчер задач сообщает о процессе, используя 662 дескриптора, 21 пользовательский объект и 12 объектов GDI, по сравнению с Tweetro, который использует 734, 37 и 19 соответственно без проблем. Что еще я могу пропустить в этой категории?
У меня много свободного места на диске, и я все равно не использую диск для чего-либо, кроме конфигурационных файлов (и все это отлично работало, прежде чем добавлять datagrids).
Моя следующая мысль заключалась в том, чтобы попытаться выполнить некоторые потенциальные "интересные" части кода datagrid и перепрыгнуть через все, что было сомнительно. Я попробовал это с помощью datagrid ArrangeOverride, но исключение, похоже, не заботило, сделал я это или нет. Кроме того, я не уверен, что это полезная стратегия. Поскольку исключение не выбрасывается до цикла цикла сообщения, и, поскольку я не могу точно знать, когда это произойдет, мне нужно будет покрыть огромное количество перестановок, запустив каждую перестановку раз, чтобы изолировать код проблемы.
Ошибка возникает в режимах отладки и выпуска. И, как заключительная фоновая заметка, объем данных, с которыми мы имеем дело здесь, является небольшим, намного меньшим, чем мои 10000-рядовые прогоны datagrid в изоляции. Это, вероятно, порядка 50-100 строк, возможно, 30-40 столбцов. И до того, как будет выбрано исключение, данные и сетки, похоже, работают и прекрасно реагируют.
Итак, почему я пришел к вам. Мои два вопроса:
- Предоставляет ли информация об ошибках какие-либо подсказки о том, что может быть проблемой?
- Какую стратегию отладки вы использовали бы для изоляции кода проблемы?
Большое спасибо за любую помощь, которую вы можете предоставить!