ゲーム開発で使用されるメモリ割り当てパターン


20

私は独自のアロケーターメソッド(メモリプールやプロファイリングなどをサポートする)の作成を研究していますが、研究を続けるにつれて、ゲーム開発でこれがどのように行われるかを探していました。

どのようなメモリ割り当て手法を使用できますか、なぜそれが優れた手法なのでしょうか?


1
本当に必要ですか?チームがこれを実装できる場合、それはチームがこれまで実装できる最も複雑なものの1つにすぎません。
Ali1S232

4
それは私にとって興味のある分野なので、私はそれについて学び、それを実装したいと
思います-chadb

...私はアロットを意味することができます場合があります...被写体が本当に面白いですと言わなければならないが、あなたの平均PCゲーム上で私は、実際のゲームの悩みというだろう
rioki

最新の標準ライブラリmallocおよびfreeまたはnewおよびdeleteのソースコードを調査しましたか?代替の割り当て戦略をアルゴリズム的または実際的に比較するための非常に有用な基盤を提供するように思われるため、私は尋ねます。それはまた、あなたが何を始めようとしているのかについての本当の洞察を提供するようです。
ルイラングホルツ

回答:


25

Game Engine Architectureには、このトピックに関する情報がいくつかあります。基本は、レベル/フレーム/などごとのメモリ要件を理解するために分析を行う必要があるということです。似ていますが、著者が何度か見たと言及しているパターンがいくつかあります。

  • スタックベースのアロケーター: これらは、メモリの大きなセグメントを一度割り当ててから、ゲームの他の場所からのリクエストに応じて、そのメモリブロック内にポインターを割り当てます。これは、メモリの割り当てに必要なコンテキスト切り替えを回避するのに役立ちます。また、独自の手法を使用して、SIMD操作の連続性または特定のアライメントを実施することができます。一部のエンジンは、1種類のリソースが上からロードされ、他のリソースが下からロードされるダブルエンドスタックも使用します。おそらく、上からLSR(ゲーム全体を通して必要となる種類の常駐)であり、下からレベルごとのデータです。
  • シングルフレームメモリ、またはダブルバッファフレームメモリ: 1つまたは2つのフレームサイクル内で発生する操作用のメモリ。これは、すべてのフレームを割り当て/割り当て解除するのではなく、メモリの追跡に使用するポインターをブロックの先頭にリセットすることで、最後のフレームのデータを単純に吹き飛ばすことができるため便利です。
  • オブジェクトプール: パーティクル、敵、発射物など、同じサイズの多くのオブジェクトのメモリブロック。これらは、プール内の最初の未使用セグメントを見つけることで簡単に連続性を実現できるため便利です。また、各オブジェクトは最後から既知のオフセットにあるため、反復も簡単になります。

著者が注目する最大のことは、メモリの断片化です。信頼できる何らかのメモリページングバックアップがあるPC向けに開発している場合、これは問題ではありませんが、コンソールのような固定メモリコンテキストでは、「メモリ不足」のリスクがあります。小さい連続したブロックのみが利用できるようにメモリが断片化されているため、大きなオブジェクトに割り当てようとするとき。そのため、彼は、上記のようなスタックベースのアロケーターにも、そのコンテンツを定期的に最適化する方法を含めることを推奨しています。

これに関連する実際のコードの詳細については、Christian Gyrlingの記事「Are we out of memory?」をお勧めします。、主にメモリ使用パターンの分析の観点から、カスタムアロケータの技術をカバーしていますが、これはメモリ管理のためのカスタムソリューションの考案にも適用できます。


1

私が見た(しかしまだ終わっていない)ことから、各ゲームはフレームワーク、ゲームエンジン、以前のバージョン(2010-> 2011)から割り当てメカニズムを継承する傾向があります。構造(データ構造が再利用可能で固定サイズの場合、または多数のタイプと可変サイズの場合)。

また、同じプロジェクト内のレベルや他のゲームオブジェクトとは異なるサウンドファイル/コンポーネントのアロケーターがありました。他のプロジェクトでは、アロケータは、そのライブラリによって管理されるコンポーネントの外部ライブラリからのみ継承されます。

最適化は本当にあなたのニーズに依存します。ただし、通常はゲームシーンに入る前に割り当てが行われ、その後メモリが再利用されます。一部のゲームでは、カスタムアロケーターを使用せずに済みます。しかし、プロセッサ、メモリ、およびデータリソースが予算化されているアクションゲームの場合、大規模な割り当てで処理時間を失う余裕はなく、断片化などの問題にメモリを浪費することはできません。

例に関しては、メモリアロケータを設定するためのいくつかのオプションがあるOGRE 3Dゲームエンジンを見るだけで始める必要があります。


0

よくある間違いは、独自のアロケーターを作成して、各システムが使用するメモリー量をより詳細に制御し、何が起こっているかをより明確に把握できるようにすることです。これを実現するはるかに良い方法は、メモリプロファイラを使用することです。私のプロファイラーMemProはその一例です。これは、すべてのメモリ使用量を追跡する完全に非侵襲的な方法であり、コールスタックワイルドカードフィルターを使用して自動的にサブシステムに分割できます。理想的には、メモリ割り当てとメモリトラッキングを完全に分離しておくことが最善であり、要件はまったく異なります。

メモリをプールに任意に分割すると、各プールにオーバーヘッドが発生するため、多くの場合有害です。実際に気付かないうちに、必要以上のメモリを使用してしまう可能性があります。無駄を減らすために、すべてをまとめておく方が常に良いです。そして、たるみはシステム全体で共有されます。

カスタムアロケーターを使用する唯一の理由は、CPUパフォーマンス(主にキャッシュの一貫性のため)と断片化の制限です。これの完璧な例は、パーティクルシステムです。すべてのパーティクルがメモリ内で連続していることを望み、多くの短期間の割り当てでメインメモリをペッパーにしたくありません。パーティション分割のもう1つの良い例は、スクリプト言語です。

汎用malloc置換の例が必要な場合は、VMemアロケーターをご覧ください。出荷されている多くのAAAゲームで使用されています。断片化を制限し、メモリフットプリントを低く保つ技術があります。これは、コンソールゲームにとって重要なことです。また、スレッドの競合が激しい場合でも非常に高速です。私のウェブサイトには、これらのテクニックに関する広範なドキュメントがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.