👏
UnityEngine.Poolの理解 コレクションに対応するObjectPoolを使おう
概要
Unity 2021から導入されたObjectPool機能について解説します。本記事では、既存の実装にObjectPoolを適用するケースを想定し、C#のコレクションに対応するObjectPoolクラスを紹介します。
ObjectPoolを使う理由
通常、新しくコレクションを作成するとヒープアロケーションが発生し、後にガベージコレクション(GC)によって開放されます。この処理負荷を抑えるためにObjectPoolパターンが活用されます。特に頻繁に同じコレクション要素を使用する場合、新規アロケーションを減らすことで効率化できます。
例えばバッチ処理で大量のオブジェクトを繰り返し作成するケースだったり、ゲーム内で同じゲームオブジェクトを大量に生成・破棄をするような場合にObjectPoolパターンを使ってみましょう。
コレクション用のObjectPoolクラス
これらのクラスは、Ge
t で取得し、使用後は 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