shared_ptrの循環参照を見つけるためのヒント/コツはありますか?
これは私が見つけようとしているものの例です-残念ながら、コード内でループを見つけることができないようです。
struct A
{
boost::shared_ptr<C> anC;
};
struct B
{
boost::shared_ptr<A> anA;
};
struct C
{
boost::shared_ptr<B> anB;
};
shared_ptrの循環参照を見つけるためのヒント/コツはありますか?
これは私が見つけようとしているものの例です-残念ながら、コード内でループを見つけることができないようです。
struct A
{
boost::shared_ptr<C> anC;
};
struct B
{
boost::shared_ptr<A> anA;
};
struct C
{
boost::shared_ptr<B> anB;
};
Valgrindの使用をお勧めします。プロセスをシャットダウンすると、リークされたすべてのメモリが表示されます。シャットダウンによって何らかの理由でサイクルが中断されない限り、サイクルはリークされたメモリとして表示され、Valgrindはコード内のどこからメモリが最初に割り当てられたかを通知します。
私はかつて信用リスクシステムの設計を担当していました(C ++では関係ありませんが)。これらは、ノードにリスクが割り当てられた非常に大きなグラフです。サイクル内にあるかどうかを見つけるための簡単なヒューリスティックがありました-500回以上トラバースした場合(正確な数値を忘れました-構成可能でした)、答えは「はい」でした。ほとんどの循環検出スキームは、このようなヒューリスティックに依存しています。
私は過去に同様の問題を抱えていました-何ヶ月も検出されなかったshared_ptr循環参照によるメモリリーク。
「キャッシュ」に注意してください。アイテム(「ウィジェット」)を処理するオブジェクト(「ファクトリー」と呼びましょう)があります。ウィジェットには、A)不変であり、B)shared_ptr<Factory>
作成者に(他のウィジェットなどを作成することもある)という特性がありました。Factoryにウィジェットキャッシュを追加するまで、すべてが正常に機能しました。ウィジェットは不変であるため、要求されるたびに同じウィジェットを返すために、それらをキャッシュすることは理にかなっています。私のキャッシュはのキャッシュだったshared_ptr<Widget>
ので、インスタントサイレントリーク。修正は明らかなので、ここでは説明しません。
最終的には、CRTからのこのようなメモリリークを検出するために使用していたプラットフォームに頼ることができました。Visual StudioのCRTには、メモリリークの検出とレポートがあります。これは、リグレッションを防ぐためにテストプログラムで有効にしました。
int main()
{
// code code code
// code code code
#ifdef _MSC_VER
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
_CrtDumpMemoryLeaks();
#endif
}
GCCにも同様の基本的なリークレポートがあると思われますが、それが何であるかはわかりません。
上記の投稿を組み合わせて使用しました。私はメモリプロファイラーを使用し、疑わしいサイクルをいくつか考え出し、weak_ptrを使用してそれらを壊しました。
以前に組み込みのCRTメモリリーク検出を使用しましたが、残念ながら、私の場合、CRT検出器のライフサイクルの後であると思われるモジュールのアンロードまで割り当てが解除されない静的シングルトンがいくつかあります。基本的に、それは誤検知である多くの噴出を与えます。
最も簡単な答えは、スマートポインタでできることはたくさんあるということだと思います。
ループを作成するたびに記録することをお勧めします(3つのオブジェクトすべてを一度に作成する場合は簡単ですが、そうでない場合は注意が必要です...)、オブジェクトを削除/リンク解除する場所で記録を確認するか、それが不可能な場合は定期的に記録します。
このオブジェクトが所有するshared_ptrsのリストを返すある種のデバッグインターフェイスを実装できます。shared_ptrに格納されているすべてのクラスに対してこれを行う必要があります。これで、トラバースできる一般的なグラフができ、それにサイクル検出アルゴリズムを使用できます。Tarjanの強く接続されたコンポーネントアルゴリズムがこれに役立つかもしれないと私は信じていますが、グラフ理論は私の強みではありません。