8

シンプルなインクリメンタルヒープアロケータを単純なコンパイルデフラグツールと組み合わせて使用​​する自己最適化メモリマネージャを記述しようとしています。C++ヒープアロケータ&STLのデフラグ

ラフスキームは、下位のメモリアドレスから上に向かってブロックを割り当て、最上位のメモリアドレスから始まるブック情報を下向きに保つことです。

メモリマネージャはスマートポインタを返すでしょう - ブーストのintrusive_ptrはブックストアの構造体にとって最も明白なようです。実際のメモリブロックを指しているので、ブロックが簡単に移動できるように間接的なレベルを与えます。

デフラグツールは、「世代」のブックマークからヒープを圧縮して処理を高速化し、一度に固定量のメモリを最適化するだけです。ブロック自体への生ポインタは、次のデフラグ・パスまで有効であり、そのような時間がパフォーマンスを改善するまで、自由に渡すことができます。

この特定のアプリケーションはコンソールゲームプログラミングなので、各フレームの最初または最後に、デフラグパスを比較的安全に行うことができます。

私の疑問は誰もがこの種の割り当て方式をSTLと組み合わせて使用​​していると思っています。私はstd :: list < intrusive_ptr>がintrusive_ptrレベルで動作しているのを見ることができますが、stlリストノード自体の割り当てについては、intrusive_ptrの次の/ prevポインタをオーバーライドするにはどうしたらいいですか?標準のヒープアロケータは、このより動的なものに沿っています。

+0

わかりません。下にあるブロックを移動するための小さなsmart_ptrハンドルがあります。しかし、基礎となるブロックにポインタがあるとどうなりますか?これらのptrsをsmart_ptrsにするにはどうすればよいですか? – jmucchiello

+0

@jmucchiello:アロケータはメモリブロックを純粋にユーザーに返すだけで、メモリのピースを持つクラスを作成していれば、そのポインタにsmart_ptrsを使用することができます。とにかく、クラスを制御し、intrusive_ptrsを使用して他のオブジェクトを '所有'するため、これは私のケースではまったく問題ありません。 – user176168

答えて

5

オブジェクトをメモリ内で動かす場合、これを完全に一般的に行うことはできません。 が移動する可能性があることがわかっているオブジェクトでのみ、これを行うことができます。また、ロック機構が必要になります。関数がオブジェクトに対して呼び出されているときは、移動できません。

理由は、C++モデル全体がメモリ上の固定ポイントにあるオブジェクトに依存しているためです。スレッドがオブジェクトのメソッドを呼び出していた場合、このスレッドは一時停止し、オブジェクトが移動し、スレッドが再開。

移動可能な別のオブジェクト(自身のサブオブジェクトを含む)への生のメモリポインタを保持しているオブジェクトは動作しません。

このようなメモリ管理の仕組みはうまくいくかもしれませんが、非常に注意する必要があります。ハンドルの実装については厳密にする必要があり、handle-> pointer lockingのセマンティクスが必要です。

STLコンテナの場合、アロケータをカスタマイズすることはできますが、固定されたRAWメモリポインタを返す必要があります。移動する可能性のある住所を返すことはできません。このため、STLコンテナを使用している場合は、ハンドルのコンテナでなければならず、ノード自体も通常の動的割り当てメモリとなります。ハンドルインダイレクションのオーバーヘッドに多すぎることがありますが、STLを使用して取得するよりハンドルコレクションの断片化に問題があります。

ハンドルを直接理解するコンテナを使用することが唯一の方法かもしれませんし、メモリー内に固定された従来のオブジェクトを使用するC++アプリケーションと比較して、さらにオーバーヘッドが発生する可能性があります。

+0

"移動した可能性があることを知っているオブジェクトでのみこれを行うことができます。 - そして/またはそれらが移動されるかもしれないことを知っているオブジェクトを含んでいるオブジェクトを持つ: - あなたは "マネージドポインタ"クラスを持つことができます。裸のポインタを使用します。 – ChrisW

+0

彼は「フレーム間」、つまり管理対象ポインタを含むオブジェクトがまったく実行されていない間のみ、デフラグを行うため、ロックする必要はありません。 – ChrisW

+0

はい、幸運なことに、アプリケーションの動作やプログラマのゲームSDKの使用方法をきめ細かく制御できるため、アプリケーション内のいずれかのアップデートで未処理のポインタを渡すことができますが、次のフレームで無効である。多くのフレームにわたって保持されるべきものへのポインタが必要な場合は、カスタムintrusive_ptr型を使用する必要があります。とにかく標準のintrusive_ptrでこの種の処理を行います。 – user176168

0

STLコンテナは、ネイキッドポインタを使用して実装されています。

カスタムアロケータはインスタンス化するときに指定することができます(アロケータを使用してポインタを初期化するため)。(割り当てられた値がネイキッドポインタに格納されるため)ポインタがどこにあるかわからないため後で変更することはできません。

代わりに、STLのサブセットを自分で実装することを検討してください。STLコンテナのバージョンは、管理対象ポインタで実装できます。

+0

これは、共有メモリ領域に 'offset_ptr'が使用されているBoost.Interprocessを見ることをお勧めします。 – gimpf

+0

カスタムSTL実装が必要であると疑われましたが、これは本当に残念です。私は、EASTLのような適切に行われたSTLの実装はそれほど悪くはないが、書き込みとテストにかなりの時間を要するだろうと思う。このようなSTLの実装を書いた人が誰か知っていますか?私はPalmがこのようなメモリ割り当てスキームを持っているのを覚えているようです。何か関係があったのかどうか疑問に思います。 – user176168

+0

私は通常、STLの小さなサブセット、すなわち(I/Oから離れて) 1つまたは2つのコンテナタイプ(およびそれらのタイプの機能のサブセットのみ)。カスタムのSTL実装は私の目的にとってはそれほど難しくありません。 – ChrisW

0

かなりよく知られている代替技術は、buddy systemです。追加のインスピレーションのためにそれを見てください。

0

コンソールゲームのプログラミングの場合は、実行時に範囲外の動的メモリ割り当てを禁止するほうがずっと簡単です。起動時には、それは達成するのが少し難しいです。

0

私は、断片化を恐れなければならないとすれば、あなたの記憶の巨大な部分であるデータ断片をじっくりと巡っていることを意味します。この美徳だけでは、これらがどうなるかはすでに分かっていますか?おそらく、レベルを下げてより具体的な意思決定を行う方がいいでしょう。そうすれば、他のコードやアプリケーションの一般的なパフォーマンスが低下することはありませんか?

リストは、ほとんどの他のSTLデータ構造と同様に、細かい断片なので、最適化されていないメモリマネージャに入れるのが非常に悪い例です。これを行うと、デフラグ・ダウンのパフォーマンスや間接費など、明らかに悪い意味があります。IMOが意味を成す唯一の構造は、配列、デク、ハッシュテーブルのメイン・チャンク、それらのものは、特定のサイズを超えてのみ、そして、それらがもうサイズ変更されないようになってからです。これらの種類のものは、一般的なものではなく、特定の解決策を呼びます。

コメントすべてがどのように判明したかに戻る。