-1

私は現在、C++ の大規模なアプリケーションに Boehm ガベージ コレクターを使用しています。それは機能しますが、GCは私の目的にはやり過ぎのようです(これを依存関係にするのは好きではありません。つま先を踏まないように、すべてのことで継続的に許容範囲を作り、GCについて考える必要があります)。たまたまそれをカバーする包括的なソリューションではなく、自分のニーズにより適したより良いソリューションを見つけたいと考えています。

私の状況では、「収集」したい特定のクラス (およびそのクラスから継承するすべてのもの) が 1 つあります。一般的なガベージ コレクションは必要ありません。この特定のクラスを除くすべての状況で、自分のメモリを簡単に管理できます。

GC を使い始める前は、参照カウントを使用していましたが、参照サイクルと頻繁な更新により、これは理想的なソリューションとは言えませんでした。

このクラスを追跡するためのより良い方法はありますか? ブーストなどの追加のライブラリ依存関係を含まないもの。

編集: オブジェクトの潜在的な寿命について概説するのがおそらく最善です。

関数は私のクラスの新しいインスタンスを作成し、それを使用する場合と使用しない場合があります。とにかく、この新しいインスタンスを呼び出し元に戻り値として渡します。呼び出し元もそれを使用する可能性があり (または使用しない可能性があります)、再びそれをスタックに戻し、最終的にはポインターを忘れ去らせるトップレベルの関数に到達します。

「可能な使用」の一部には、将来どこかで使用するためにポインターを保存する(または保存しない)他の関数にポインターを渡すことが含まれるため、トップレベルのポインターを削除することはできません。

これが、私が解決しようとしている問題をよりよく示していることを願っています。現在、Boehm Garbage Collector で解決していますが、可能であれば、よりシンプルで依存関係のないソリューションが必要です。

4

3 に答える 3

1

組み込みシステムの世界、またはリアルタイム イベント クリティカルなプログラムでは、ガベージ コレクションは嫌われています。動的メモリを使用する点は悪いです。

動的メモリ割り当てでは、断片化が発生します。ガベージ コレクターを使用して、メモリを定期的に配置し、解放された連続したブロックを結合するなど、断片化を減らします。主な問題は、この最適化または GC の実行を いつ実行するかです。

いくつかの代替案:

システムを再設計して、動的メモリ割り当てを回避します。
静的バッファを割り当てて使用します。たとえば、RTOS システムでは、メッセージを動的に割り当てるのではなく、事前にメッセージ用の領域を割り当てます。

ヒープではなく、スタックを使用します。 可能であれば、動的に割り当てられた変数にスタックを使用します。変数が関数の実行を超えて存続する必要がある場合、これは良い考えではありません。

可変サイズのデータ​​に制限を設けます。
静的バッファーと共に、可変長データまたは不明なサイズの受信データに制限を設けます。これは、入力を停止できない場合、受信データを一時停止するか、複数のバッファリングを行う必要があることを意味する場合があります。

独自のメモリ アロケータを作成します。
異なるサイズのブロックを割り当てるメモリ プールを多数作成します。これにより、断片化が減少します。たとえば、小さなブロックの場合、abitsetを使用して、使用中のバイトと使用可能なバイトを判別できます。おそらく、64 バイト ブロック用の別のプールが必要です。すべてはシステムのニーズに依存します。

于 2013-11-10T19:09:24.033 に答える
0

単一のクラスに関連付けられたメモリ割り当てに特別な処理が本当に必要な場合は、そのクラスの new 演算子のオーバーロードを検討する必要があります。

class MyClass
{
public:
  void *operator new(size_t);
  void operator delete(void *);
}

これらの演算子を実装して、メモリを追跡するために必要なことは何でも行うことができます: 特別なプールから割り当てる、追跡のためにリンクされたリストに参照を配置するなど。

void* MyClass::operator new(size_t size)
{
    void *p = my_allocator(size);  // e.g., instead of malloc()
    // place p on a linked list, etc.
    return p;
}

void MyClass::operator delete(void *p)
{
    // remove p from list...
    my_free(p);
}

次に、保持しているリストをウォークスルーして、現在割り当てられている MyClass のすべてのインスタンスを検査し、状況に応じてインスタンスを GC する外部コードを作成できます。

于 2013-11-10T19:46:25.060 に答える
0

記憶に関しては、常に明確な所有権と生涯の知識を持つように努める必要があります。ライフタイムは、(他の要因と同様に) メモリをどこから取得するかを決定します。つまり、有効なスコープのスタック、再利用されるプールなどです。所有権は、メモリをいつ解放するかを示します。あなたの場合、GC が所有権を持ち、いつ解放するかを決定します。参照カウントでは、ラッパー クラスがこのロジックを実行します。手動のメモリ管理を使用すると、所有権が不明確になると、コードの保守が難しくなります。解放後の使用、二重解放、およびメモリ リークを避ける必要があります。

問題を解決するには、誰が所有権を保持する必要があるかを判断します。これにより、使用するアルゴリズムが決まります。GC と参照カウントは一般的な選択肢ですが、無限に多くあります。所有権が不明な場合は、追跡を担当する第三者に譲渡してください。所有権が共有されている場合は、おそらく特殊なクラスを介して強制することにより、すべての関係者が所有権を認識していることを確認してください。これは単純な規則によって強制することもできます。つまり、タイプ foo のオブジェクトは、タイプ bar の ptr を内部で保持してはなりません。それらを所有していないためです。また、所有している場合、それらが常に有効であると想定することはできず、最初に有効性をチェックする必要がある可能性があります。等。

これを判断するのが難しい場合は、コードが非常に複雑であることを示している可能性があります。もっと簡単な方法で作ることはできますか?

メモリがどのように使用され、アクセスされるかを理解することは、メンテナンスとパフォーマンスの最適化のためにクリーンなコードを記述するための鍵です。これは、使用する言語に関係なく当てはまります。

幸運を祈ります。

于 2013-11-13T04:16:57.480 に答える