2

参照カウントメカニズムを実装するオブジェクトがあります。それへの参照の数がゼロになると、オブジェクトは削除されます。

オブジェクトを使い終わっても、オブジェクトが削除されることはありません。これは、メモリの過剰使用につながります。私が持っているのはオブジェクトへの参照の数だけであり、適切なクリーンアップコードを記述できるように、オブジェクトを参照する場所を知りたいです。

ソースファイルでgrepを実行せずにこれを実現する方法はありますか?(それは非常に面倒です。)

4

5 に答える 5

6

C ++で参照カウント(refcounting)を正しく実行するための大部分は、Resource Allocation Is Initializationを使用することであるため、誤って参照をリークすることははるかに困難です。ただし、これはrefcountsですべてを解決するわけではありません。

そうは言っても、参照を保持しているものを追跡するデバッグ機能をrefcountingに実装できます。その後、必要に応じてこの情報を分析し、リリースビルドから削除できます。(DEBUGマクロの使用方法と同じ目的の構成マクロを使用してください。)

正確にどのように実装するかは、すべての要件によって異なりますが、これを行うには2つの主な方法があります(違いの簡単な概要を含む)。

  • 参照されるオブジェクト自体に情報を格納します
    • デバッガーからアクセス可能
    • 実装が簡単
  • 参照が取得または解放されるたびに、特別なトレースファイルに出力されます
    • プログラムが終了した後も(異常な場合でも)引き続き使用可能
    • デバッガーで実行せずに、プログラムの実行中に使用できます
    • 特別なリリースのビルドでも使用でき、分析のために返送されます

特定のオブジェクトを何が参照しているかを知るという基本的な問題は、一般的に解決するのが難しく、いくつかの作業が必要になります。比較してください:あなたの住所や電話番号を知っているすべての人や企業を教えていただけますか?

于 2010-01-10T08:22:52.933 に答える
2

参照カウントの既知の弱点の1つは、循環参照がある場合、つまり(最も単純な場合)、あるオブジェクトが別のオブジェクトへの参照を持ち、そのオブジェクトが前のオブジェクトへの参照を持っている場合に機能しないことです。これは問題ではないように聞こえますが、親ノードへの逆参照を持つバイナリツリーなどのデータ構造には問題があります。

参照されている(解放されていない)オブジェクトの「逆」参照のリストを明示的に指定しないと、誰がそれを参照しているかを把握する方法がわかりません。

以下の提案では、ソースを変更したくない、または変更したい場合は少しだけ変更したくないと思います。

もちろん、ヒープ/フリーストア全体を調べて、解放されていないオブジェクトのメモリアドレスを検索することもできますが、そのアドレスが見つかった場合、実際メモリアドレス参照であるとは限りません。それは、他の何よりも、任意のランダムな浮動小数点数である可能性もあります。ただし、見つかった値が、アプリケーションがオブジェクトに割り当てたメモリのブロック内にある場合は、それが実際に別のオブジェクトへのポインタである可能性が少し向上します。

このアプローチに対する1つの可能な改善は、使用するメモリアロケータ(グローバルなど)を変更して、operator new割り当てられたすべてのメモリブロックとそのサイズのリストを保持することです。(これを完全に実装するoperator deleteと、解放されたメモリブロックのリストエントリが削除されます。)これで、プログラムの最後に、解放されていないオブジェクトのメモリアドレスを検索する場所がわかります。プログラムが実際に使用したメモリブロックのリスト。

正直なところ、上記の提案は私にはあまり信頼できるとは思えません。ただし、カスタムグローバルoperator newを定義するとoperator delete、問題を解決するために適切な方向にログ/トレースが実行されます。

于 2010-01-10T08:27:33.720 に答える
1

say関数addRef()release()メンバー関数を備えたクラスがあり、各インスタンスの参照カウントを増減する必要があるときにこれらを呼び出し、問題を引き起こすインスタンスはヒープ上にあり、生のポインターで参照されていると想定しています。最も簡単な修正は、制御されたオブジェクトへのすべてのポインターを次のように置き換えることです。boost::shared_ptr. これは驚くほど簡単に実行でき、独自の参照カウントを省くことができるはずです。前述の関数を何も行わないようにするだけです。コードに必要な主な変更は、ポインターを渡したり返したりする関数のシグネチャです。他に変更する場所は、イニシャライザ リスト (ポインタを null に初期化する場合) と if() ステートメント (ポインタを null と比較する場合) です。ポインターの宣言を変更すると、コンパイラーはそのような場所をすべて見つけます。

を使用したくない場合shared_ptr(おそらく、参照カウントをクラス固有のままにしたい場合) は、クラスを処理するためだけに独自の単純なスマート ポインターを作成できます。次に、それを使用してクラス オブジェクトの有効期間を制御します。したがって、たとえば、ポインタの割り当てが生のポインタで行われ、「手動で」 を呼び出す代わりに、自動的addRef()に を含むスマート ポインタ クラスの割り当てを行うだけです。addRef()

于 2010-01-10T13:28:33.317 に答える
0

コードを変更せずに何かを行うことは不可能だと思います。コードを変更すると、たとえば、参照カウントを増やすオブジェクトのポインターを覚えて、残っているポインターを確認し、デバッガーで調べることができます。可能であれば、オブジェクト名など、より詳細な情報を保存します。

于 2010-01-10T08:22:05.930 に答える
0

私は自分のニーズに合わせて作成しました。コードをこれと比較して、何が欠けているかを確認できます。完璧ではありませんが、ほとんどの場合はうまくいくはずです。 http://sites.google.com/site/grayasm/autopointer

私がそれを使用するとき:

util::autopointer<A> aptr=new A();

私は決してこのようにはしません:

A* ptr = new A();
util::autopointer<A> aptr = ptr; 

そして後で ptr でいっぱいになり始めます。それは許可されていません。さらに、このオブジェクトを参照するために aptr のみを使用しています。私が間違っている場合は、修正を得るチャンスがあります。:) じゃあ!

于 2010-01-10T09:44:56.357 に答える