Zenn
👏

UnityEngine.Poolの理解 コレクションに対応するObjectPoolを使おう

2025/02/06に公開

概要

Unity 2021から導入されたObjectPool機能について解説します。本記事では、既存の実装にObjectPoolを適用するケースを想定し、C#のコレクションに対応するObjectPoolクラスを紹介します。

ObjectPoolを使う理由

通常、新しくコレクションを作成するとヒープアロケーションが発生し、後にガベージコレクション(GC)によって開放されます。この処理負荷を抑えるためにObjectPoolパターンが活用されます。特に頻繁に同じコレクション要素を使用する場合、新規アロケーションを減らすことで効率化できます。

例えばバッチ処理で大量のオブジェクトを繰り返し作成するケースだったり、ゲーム内で同じゲームオブジェクトを大量に生成・破棄をするような場合にObjectPoolパターンを使ってみましょう。

コレクション用のObjectPoolクラス

これらのクラスは、Get で取得し、使用後は Release で返却するだけのシンプルな仕組みです。

文字列リストの処理サンプル

以下は ListPool を用いた文字列処理の例です。

UnityEngine.Pool.ListPoolを使ってみる
using UnityEngine;
using UnityEngine.Pool;

public class Example : MonoBehaviour
{
    void Start()
    {
        // string型のListPoolを取得
        var list = ListPool<string>.Get();

        // 通常のListと同じように利用可能
        list.Add("Hello");
        list.Add("Unity");
        list.Add("World");

        foreach (var item in list)
        {
            Debug.Log(item);
        }

        // 使用後は必ず返却
        ListPool<string>.Release(list);
    }
}

ObjectPoolを使うべき場面

  • List<string> を何度も繰り返し利用する場合
  • ファイルのバッチ処理などで頻繁に文字列リストを作成するケース

使用を検討すべきケース

  • Span<T> を使ってゼロアロケーション化できないか?
  • 毎回 List を生成せず、グローバルなリストを使い回せないか?
  • 文字列処理なら StringBuilder や ZString の方が適切ではないか?

using ステートメントで Release を省略する改良サンプルコード

using ステートメントを使うことで、明示的な Release を不要にできます。

usingステートメントで自動開放
using UnityEngine;
using UnityEngine.Pool;

public class Example : MonoBehaviour
{
    void Start()
    {
        // usingステートメントを利用して自動解放
        using var _ = ListPool<string>.Get(out var list);

        list.Add("Hello");
        list.Add("Unity");
        list.Add("World");

        foreach (var item in list)
        {
            Debug.Log(item);
        }
        // スコープを抜けると自動でRelease
    }
}

参考記事

Discussion

ログインするとコメントできます