状況
しばらくの間メモリを解放しない大規模なWPFアプリケーションを実行しています。メモリは最終的に解放されるため、実際のメモリリークではありません。通常、これは問題とは見なされないことを私は知っています。残念ながら、これはWPFコマンドインフラストラクチャに関連するパフォーマンスの問題になります。詳細については、以下を参照してください。
調査結果
一般的なユースケースを実行する自動テストがあります。一部のケースは正常に機能しており、時間内にメモリを解放しています。他の人は、クライアントが最小化されるか、新しいウィンドウが開かれるか、Gen2コレクションをトリガーする他の条件が発生するまでメモリを占有しています。
•ANTSを使用すると、オブジェクトにはGCルートがありませんが、ファイナライズが必要な他のオブジェクトへの参照が多数あることがわかります。
•WinDbgは、ファイナライズの準備ができているオブジェクトを表示しません。
•複数実行するとGC.Collect()
、GC.WaitForPendingFinalizers()
メモリが完全に解放されます。
•どのUIアクションが高メモリ状態を引き起こしているのかはわかっていますが、疑わしいコードを特定できませんでした。
質問
このような問題のデバッグに関するアドバイスをいただければ幸いです。
WPFCommandManagerの背景
WPF CommandManagerは、イベントを発生_requerySuggestedHandlers
させるためのWeakReferences()のプライベートコレクションを保持します。CanExecuteChanged
処理CanExecuteChanged
にはかなりのコストがかかります(特に、のEventRouteを見つけることはCanExecute
明らかにですRoutedEvent
)。CommandManagerは、コマンドを実行できるかどうかを再クエリするように感じるときはいつでも、このコレクションを繰り返し処理CanExecuteChanged
し、それぞれのコマンドソースでイベントを呼び出します。
参照されるオブジェクトのGCハンドルがある限り、WeakReferencesはそのコレクションから削除されません。オブジェクトが収集されていない間、CommandHelperはCanExecute
これらの要素(ButtonBaseまたはMenuItems)のイベントを処理し続けます。ガベージが多い場合(この場合のように)、CanExecuteイベントハンドラーの呼び出しが非常に多くなり、アプリケーションが非常に遅くなる可能性があります。