9月26日編集
完全な背景については、以下を参照してください。tl;dr: データ グリッド コントロールが異常な例外を引き起こしています。原因を特定して解決策を見つけるためのヘルプを探しています。
これをさらに絞り込みました。私はより小さなテストアプリで動作を再現し、より信頼性の高い不規則な動作をトリガーすることができました.
スレッド化と (私が思うに) メモリの問題の両方を確実に排除できます。新しいアプリはタスクやその他のスレッド化/非同期機能を使用せず、DataGrid に表示されているオブジェクトのクラスに定数を返すプロパティを追加するだけで、未処理の例外をトリガーできます。これは、問題が管理されていないリソースの枯渇にあるか、または私がまだ考えていないことにあることを示しています。
改訂されたプログラムはこのように構成されています。EntityCollectionGridView
ラベルとデータ グリッドを持つユーザー コントロールを作成しました。List<TestClass>
コントロールの Loaded イベント ハンドラーで、 1000 行または 10000 行のデータ グリッドにを割り当て、グリッドが列を生成できるようにします。このユーザー コントロールは、ページのイベントで MainPage.xaml で 2 ~ 4 回インスタンス化されますOnNavigatedTo
(またはLoaded
、問題ではないようです)。例外が発生した場合は、MainPage が表示された直後に発生します。
興味深いことに、動作は表示される行数によって変化するようには見えません (10000 行で確実に機能するか、各グリッドに 1000 行のみで確実に失敗します) が、すべてのグリッドの列の総数によって異なります。所定の時間にロードされます。表示するプロパティが 20 の場合、4 つのグリッドで問題なく動作します。35 個のプロパティと 4 個のグリッドがある場合、例外がスローされます。しかし、2 つのグリッドを削除すると、35 個のプロパティを持つ同じクラスが正常に機能します。
TestClass
20 列から 35 列にジャンプするために追加するすべてのプロパティは、次の形式であることに注意してください。
public string StringXYZ { get { return "asdfasdfasdfasdfasf"; } }
そのため、バッキング データに追加のメモリはありません (繰り返しますが、いずれにしてもメモリ プレッシャーが問題になるとは思いません)。
皆さんはどう思いますか?繰り返しますが、タスク マネージャーのハンドル/ユーザー オブジェクトなどは問題ないように見えますが、他に不足している可能性があるものはありますか?
元の投稿
私は、Silverlight Toolkit DataGrid の WinRT への移植に取り組んでおり、単純なテスト (さまざまな構成と最大 10000 行) で十分に機能しました。ただし、それを別の WinRT アプリに埋め込もうとしたときに、散発的な例外 (App.UnhandledException ハンドラーで発生した System.Exception 型) が発生し、デバッグが非常に困難であることがわかりました。
Not enough quota is available to process this command. (Exception from HRESULT: 0x80070718)
エラーは一貫して再現可能ですが、決定論的ではありません。つまり、アプリを実行するたびに発生させることができますが、まったく同じ一連の手順を同じ回数実行しても常に発生するとは限りません。このエラーは、(たとえば) データグリッドの ItemsSource を変更するときではなく、ページ遷移 (新しいページに進むか、前のページに戻るか) で発生するようです。
アプリケーションの構造は、基本的に階層を介した再帰アクセスであり、各階層レベルでページが表示されます。階層内の現在のノードのページには、各子ノードといくつかの孫ノードが表示され、サブノードのデータグリッドが表示される場合があります。実際には、次のナビゲーション構造でこれを一貫して再現します。
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
典型的なテスト シナリオは、ルートから開始し、子に移動し、孫に移動し、子に戻り、再び孫に移動しようとすると、上記の例外で失敗します。しかし、Grandchild を初めてヒットしたときに失敗したり、失敗する前に数回前後に移動したりする可能性があります。
コール スタックには、未処理の例外イベント ハンドラーであるマネージ フレームが 1 つだけあります。これは非常に役に立ちません。混合モードのデバッグに切り替えると、次のようになります。
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++
user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallWinProcCheckWow@36() + 0xbd bytes
user32.dll!_DispatchMessageWorker@8() + 0xf8 bytes
user32.dll!_DispatchMessageW@4() + 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++
SHCore.dll!_SHWaitForThreadWithWakeMask@12() + 0xceab bytes
kernel32.dll!@BaseThreadInitThunk@12() + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
これは、私が間違っていることは、アプリのメッセージ ループで少なくとも 1 サイクル後まで登録されないことを示しています (また、「デバッグ | 例外...」を使用して、スローされたすべての例外を中断しようとしました。何も投げたり飲み込んだりしていないことがわかります)。私が見る興味深いスタック フレームは、、、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
...しかし、それは私にとってもあまり意味がありません (関係ないかもしれません)。
私が思いつくことができる3つの理論は次のとおりです。
- メモリ プレッシャー。しかし、物理メモリの 24% が空いていて、アプリが消費するメモリが 100MB 未満で、これに遭遇しました。それ以外の場合、アプリはしばらくナビゲートして400MBのメモリをラックアップしても問題はありません
- スレッドの問題、ワーカー スレッドから UI スレッドへのアクセスなど。実際、バックグラウンド スレッドでデータ アクセスが発生しています。しかし、これは WinForms 環境と Outlook プラグインで非常に信頼性の高い (移植された) フレームワークを使用しており、スレッドの使用は安全だと思います。さらに、ListViews などにバインドするだけで問題なく、このアプリで同じデータを使用できます。最後に、Grandchild ノードは、最初のデータグリッドで行を選択すると、行の詳細項目の要求が開始され、2 番目のデータグリッドに表示されるように構成されます (最初は空で、例外を防ぐことなくそのままにしておくことができます)。これはページ遷移なしで発生し、選択をいじることを選択している限り問題なく動作します。しかし、Child に戻るとすぐに死ぬかもしれません。
- ある種のリソースの枯渇、おそらく GUI ハンドル。しかし、私はこのシステムにそれほどプレッシャーをかけているとは思いません。1 回の実行で、例外ハンドラーを中断すると、タスク マネージャーは 662 個のハンドル、21 個のユーザー オブジェクト、および 12 個の GDI オブジェクトを使用するプロセスを報告しますが、Tweetro はそれぞれ 734 個、37 個、および 19 個を問題なく使用しています。このカテゴリで他に何が不足している可能性がありますか?
十分な空きディスク容量があり、とにかく構成ファイル以外にはディスクを使用していません (データグリッドを追加する前はすべて正常に機能していました)。
私が次に考えたのは、データグリッド コードの潜在的な「興味深い」部分のいくつかをステップスルーして、疑わしい部分を飛び越えようとすることでした。私はデータグリッドの ArrangeOverride でそれを試しましたが、例外は私がそれをしたかどうかを気にしていないようでした。また、これが有用な戦略であるかどうかはわかりません。例外はメッセージ ループのサイクルの後までスローされず、例外がいつ発生するかを確実に知ることができないため、膨大な数の順列をカバーし、各順列を大量に実行する必要があります。回、問題のコードを切り分けます。
このエラーは、デバッグ モードとリリース モードの両方でスローされます。そして、最後のバックグラウンド ノートとして、ここで扱っているデータの量は少なく、データ グリッドを単独で実行した 10000 行よりもはるかに小さいです。おそらく 50 ~ 100 行程度で、おそらく 30 ~ 40 列です。例外がスローされる前は、データとグリッドは正常に動作しているように見えます。
だから、それが私があなたのところに来る理由です。私の2つの質問は次のとおりです。
- エラー情報は、何が問題であるかについてのヒントを与えてくれますか?
- 問題のコードを切り分けるために、どのデバッグ戦略を使用しますか?
あなたが提供できる助けを前もって感謝します!