C++ ヒープ アロケーターと STL のデフラグ
-
12-09-2019 - |
質問
私は、単純な増分ヒープ アロケータを単純な圧縮デフラグ ツールと組み合わせて使用する、自己デフラグ メモリ マネージャーを作成しようとしています。
大まかなスキームは、最も低いメモリ アドレスから上に向かってブロックを割り当て、最も高いメモリ アドレスから始まる簿記情報を下に向かって割り当てることです。
メモリ マネージャはスマート ポインタを返します。boost の intrusive_ptr は、実際のメモリ ブロックを指し示すブックキーピング構造体にとって最も明白であるように見えます。これにより、ブロックを簡単に移動できるように、あるレベルの間接性が与えられます。
デフラグ ツールは、プロセスを高速化するために「生成」ブックマークから開始してヒープを圧縮し、一度に固定量のメモリのみをデフラグします。ブロック自体への生のポインターは、次のデフラグ パスまで有効であるため、パフォーマンスが向上するまで自由に渡すことができます。
これの具体的な用途はコンソール ゲームのプログラミングであるため、各フレームの最初または最後にデフラグ パスを比較的安全に実行できます。
そこで私の質問は、誰かがこの種の割り当てスキームを STL と組み合わせて使用したことがあり、それが私が推測するように STL を完全に破壊してしまう可能性があるということです。std::list< intrusive_ptr > が intrusive_ptr レベルで動作しているのはわかりますが、stl リスト ノード自体の割り当てはどうなっているのでしょうか。とにかく next/prev ポインターを intrusive_ptr 自体にオーバーライドするためのものがあるのでしょうか、それとも単に標準のヒープ アロケータと、より動的なものです。
解決
メモリ内でオブジェクトを移動する場合、これを完全に汎用的に行うことはできません。これを実行できるのは、次のオブジェクトに対してのみです。 知る 彼らが感動するかもしれないからです。ロック機構も必要になります。オブジェクトに対して関数が呼び出されている場合、オブジェクトを移動することはできません。
その理由は、C++ モデル全体がメモリ内の固定点にあるオブジェクトに依存しているためです。そのため、スレッドがオブジェクトのメソッドを呼び出しているときに、このスレッドが一時停止されてオブジェクトが移動した場合、スレッドが再開されたときに惨事が発生することになります。
移動される可能性のある別のオブジェクト (それ自体のサブオブジェクトを含む) への生のメモリ ポインターを保持するオブジェクトは機能しません。
このようなメモリ管理スキームは機能する可能性がありますが、十分に注意する必要があります。ハンドルとハンドル->ポインタのロック セマンティクスの実装については厳密である必要があります。
STL コンテナの場合、アロケータをカスタマイズできますが、固定の生メモリ ポインタを返す必要があります。移動する可能性のあるアドレスを返すことはできません。このため、STL コンテナを使用している場合、それらはハンドルのコンテナである必要があり、ノード自体は動的に割り当てられる通常のメモリになります。ハンドルの間接化でのオーバーヘッドが多すぎるにもかかわらず、STL を使用した場合よりもハンドル コレクションの断片化で問題が発生する場合があります。
ハンドルを直接理解するコンテナを使用することが唯一の方法かもしれませんが、その場合でも、メモリに固定された従来のオブジェクトを使用する C++ アプリケーションと比較すると、依然として多くのオーバーヘッドが発生する可能性があります。
他のヒント
STL コンテナは、ネイキッド ポインターを使用して実装されます。
カスタム アロケータをインスタンス化するときにカスタム アロケータを指定できます (アロケータを使用してポインタを初期化します) が、(割り当てられた値はネイキッド ポインタに格納されるため) それらのポインタがどこにあるのかわからないため、カスタム アロケータを指定することはできません。後で変更してください。
代わりに、STL のサブセットを自分で実装することを検討してください。STL コンテナーのバージョンは、マネージド ポインターを使用して実装できます。
かなりよく知られている代替テクニックは、 バディシステム. 。追加のインスピレーションを得るために、これを参照してください。
これがコンソール ゲームのプログラミングの場合は、実行時にスコープ外の動的メモリ割り当てを禁止する方がはるかに簡単です。そして起動時ですが、これを達成するのは少し困難です。
これについての私の見解は、断片化を恐れる必要があるということは、メモリの膨大な部分を占めるデータ断片をやりくりしていることを意味し、その利点だけでは、多くのデータを保持することはできないということです。これらが何になるかはもう知っていますか?おそらく、レベルを 1 つ下げて、より具体的な決定を下して、他のコードやアプリケーションの全体的なパフォーマンスへの影響を少なくする方がよいでしょうか?
リストは、他のほとんどの STL データ構造と同様、小さな断片の集まりであるため、デフラグメモリ マネージャーに組み込むには非常に悪い例です。これを行うと、デフラグツールのパフォーマンスの低下や間接コストなど、あらゆる種類の明らかな悪影響が生じます。IMO で意味のある唯一の構造は、連続した構造です。配列、デク、ハッシュテーブルのメイン チャンク、これらのものであり、特定のサイズを超え、サイズが変更されなくなった後にのみ使用されます。このような問題では、やはり、一般的な解決策ではなく、具体的な解決策が必要になります。
すべてがどうなるかについてコメントしてください。