13

状況

しばらくの間メモリを解放しない大規模な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イベントハンドラーの呼び出しが非常に多くなり、アプリケーションが非常に遅くなる可能性があります。

4

2 に答える 2

5

アプリケーションの1つで同じ問題が発生します。私が呼び出すウィンドウを開くたびに:

GC.GetTotalMemory(true);

これにより、GCは待機せずにすぐにメモリをクリーンアップします。この方法の詳細については、こちらをご覧ください。

http://msdn.microsoft.com/en-us/library/system.gc.gettotalmemory.aspx

CanExecuteの呼び出しの問題については、同じパフォーマンスの問題があるため、回避しようとしています。代わりに、ビューモデルのプロパティを使用して、XAMLのビジュアル要素のIsEnabledプロパティをビューモデルのプロパティにバインドします。このようにして、全体的なパフォーマンスが向上し、CanExecute呼び出しがなくなります。

これがお役に立てば幸いです。

于 2012-11-29T12:53:44.303 に答える
0

CLRProfilerをお試しください。ダウンロードリンクはこちらです。これは、割り当てられ、破棄され、存続したイベントハンドラーを示しています。このツールを使用することで、根本的な原因を突き止めることができると確信しています。Advanced .NET Debuggingの本には、デバッグに適したツールがいくつかリストされています。ヘルプが必要な場合は、この本を読むことができます。

于 2012-11-28T07:19:58.270 に答える