私たちは大規模なメモリリーク分析を行ってきましたが、その要因の1つは、イベントのデリゲートが削除されなかったために、オブジェクトが十分に速く(場合によっては永久に)GCされないことでした。
FXCopでルールを記述して、デリゲートをハンドラーから確実に削除する方法について、誰かアイデアがありますか?
私はこれを見たばかりなので、そこで詳細を尋ねます。
私たちは大規模なメモリリーク分析を行ってきましたが、その要因の1つは、イベントのデリゲートが削除されなかったために、オブジェクトが十分に速く(場合によっては永久に)GCされないことでした。
FXCopでルールを記述して、デリゲートをハンドラーから確実に削除する方法について、誰かアイデアがありますか?
私はこれを見たばかりなので、そこで詳細を尋ねます。
より具体的にする必要があります。一般的なケースでは、サブスクライバーはパブリッシャーよりも寿命が短いため、すべてのイベントデリゲートがサブスクライブ解除されたことを確認する必要はありません。また、メモリリークは、サブスクライバーがパブリッシャーよりも存続期間が長いように見える場合にのみ発生します。したがって、参照があり、GCがパブリッシャーオブジェクトを収集できません。
ここで、比較的寿命の短いオブジェクトでイベントをサブスクライブした場合、最終的にはサブスクライブを解除することを確認する必要があります。
この場合に思いつくヒューリスティック:すべてのローカル変数オブジェクト(現在のコードブロック{}によってスコープされている)と、明示的に破棄するすべてのオブジェクトを分析します。これらのオブジェクトのすべてのイベントについて、それらをサブスクライブした回数とサブスクライブを解除した回数をカウントします。最初の数値が大きい場合は、警告を発します。
もちろん、それですべてのケースをカバーできるわけではありませんが、この問題のすべてのケースを静的なアプローチでカバーできるわけではないと思います。十分に優れた方法が必要です。
動的分析とコードレビューの利点については、質問とは関係のない別のトピックであるため、ここでは説明しません。
さて、実際のチェックを実装する問題のほかに(私の意見では、これはパスカバレッジに非常に似ているため、実用的ではありません)-新しいFxCopルールを作成する方法は次のとおりです。
最初に私を一度助けたいくつかの記事:
単純なルールを実装することは大したことではありません。プロジェクトでは、埋め込みリソースとしてRules.xmlファイルが必要です(ここを参照)。Check()メソッドからクラスを派生させBaseIntrospectionRule
、コードを追加します。
public override ProblemCollection Check( TypeNode typeNode )
{
if( type.IsPublic )
{
Problems.Add( new Problem( ... ) );
}
return Problems;
}
私はこれを数回前に行いました。説明どおりに機能することを願っています:)
すべてのイベントサブスクリプションはWeakReferencesを介して処理する必要があるというルールを強制できますか?これは、プログラムの実際のフローを分析するよりも簡単に実装できるはずだと思います。
ハンドラーを実装しているオブジェクトが、イベントを含むオブジェクトへの参照を何らかの形で持っていると想定しても安全ですか?その場合は、別の方法でサイクルを中断する方法を考えたほうがよいでしょう。
しばらく前に、ASP.NETページのイベントハンドラーで同様のことが起こっていました。ハンドラーを実装したオブジェクトにもページへの参照がありました。可能な限り多くのリンクをアーキテクチャ的に切断した後、残りのいくつかはWeakReferencesに変更されました。これ以上のメモリの問題はありません!