Edited at

GameProgrammingPatterns: 第19章 オブジェクトプール

More than 1 year has passed since last update.


概要



フラグメンテーションの呪い


  • ゲーム/モバイル機器のメモリは少ない

  • 効率の良いコンパクトメモリマネージャ(無駄な領域解放/断片化解消)が出来るのは稀

  • 結果としてフラグメンテーション(ヒープ内の空きスペースが細切れになり、十分なメモリが存在しても再割当て出来ない)状態が起こる可能性がある



フラグメンテーションの回避


  • 例えば、ゲーム開始に大きなメモリ領域を確保し、終了まで開放しない

  • この方法では進行中の生成/破棄することが難しい



オブジェクトプール


  • 一度生成したオブジェクトを使いまわすのが肝



  • 再利用可能なオブジェクト群を管理するプールクラスを定義

  • 初期化時に必要量を未使用状態で生成

  • オブジェクトを使用する場面で、プールクラスは未使用のオブジェクトを使用中状態にして返す



  • オブジェクトが不要になった時は未使用状態に戻す

  • フラグメンテーションを気にせず、オブジェクトを使用できる

  • 都度都度のメモリ割り当てと解放のコストを避けることが出来る



推奨される場面


  • オブジェクトの生成と破壊が頻繁に必要な場合

  • オブジェクトのサイズが似ている場合

  • フラグメンテーションを起こす場合

  • 各オブジェクトがデータベースやネットワーク等のリソースをカプセル化してあり、リソース取得のコストが高く、再利用が可能である場合



使用上の注意



大きなプールサイズ


  • 必要最小限なプールサイズを指定する



一時期に利用出来るオブジェクト数が固定される


  • オブジェクトの生成を行わせない (e.g: パーティクル等)

  • 古いオブジェクトを再利用する (e.g: 効果音)

  • プールサイズを動的に増やす



各オブジェクトのメモリサイズが固定される


  • 最大のサイズでも収まるプールスロットが必要になってしまう

  • オブジェクトのサイズによってプールを分けるべき



再利用されるオブジェクトは自動的に初期化されない


  • 利用時等に明示的に初期化する必要がある



使用されていないオブジェクトがメモリに残る


  • オブジェクトプールはオブジェクトの解放まで行われない


    • 全て使用されなくなった場合には他のオブジェクトへの参照をクリアする





オブジェクトプールの拡張


  • オブジェクトとプールの結合させない


    • 仮により汎用的で再利用可能なプールを作りたい場合

    • 使用中かどうかはビットフィールドで管理する



template <class TObject>

class GenericPool
{
private:
static const int POOL_SIZE = 100;

TObject pool_[POOL_SIZE];
bool inUse_[POOL_SIZE];
}



オマケ: Unityにおけるオブジェクトプール