---
title: オブジェクトのプーリングと再利用
product: Unity Editor
version: '6000.0'
latest_version: '7000.0'
status: This page documents version 6000.0. The latest version is 7000.0.
canonical: https://docs.unity.com/ja-jp/engine/6000.0/manual/scripting/optimization/performance-optimizing-code-managed-memory/reusable-code
latest_url: https://docs.unity.com/ja-jp/engine/7000.0/manual/scripting/optimization/performance-optimizing-code-managed-memory/reusable-code.md
generated_at: 2026-11-14T04:02:30.987Z
locale: ja-jp
---

# オブジェクトのプーリングと再利用

> UnityのUnityEngine.Pool APIを使用することで、CPUロードとガベージ コレクターのオーバーヘッドを削減できます。これにより、頻繁に使用されるオブジェクトを繰り返し作成/破棄するのではなく、それらをプールして再利用できます。

オブジェクトプールと再利用は、頻繁に使用されるオブジェクトのインスタンスをプールに返し、そこから取得して再使用できるプログラミングパターンです。オブジェクトプールは、新しいオブジェクトインスタンスのインスタンス化と破棄を繰り返すことによって発生するオーバーヘッドを削減し、割り当てと割り当て解除の全体的な数を制限します。これは、ガベージコレクション(GC)オーバーヘッドの最小化とCPUのロード軽減に役立ちます。

GameObjects はプールできますが、配列、リスト、ディクショナリなどのコレクションタイプなど、頻繁に使用する他のタイプもプールできます。独自のプーリング ロジックを作成することもできますが、Unity は便宜上、`UnityEngine.Pool` 名前空間に、Pooling GameObjects といくつかのコレクション タイプのための実装を備えた API のセットを提供します。

> **Note:**
>
> 他の多くのコア Unity API と同様に、`UnityEngine.Pool` API はスレッドセーフではなく、メインスレッドからのみ安全に呼び出すことができます。

## Pooling and reusing GameObjects （ゲームオブジェクトのプールと再利用）##pooling-and-reusing-gameobjects

発射物など、ゲーム内のオブジェクトの中には、シーン内に同時に数個しか存在しないものであっても、繰り返し頻繁に登場するものがあります。発射されるたびにプレハブから新しい砲弾オブジェクトをインスタンス化する代わりに、ゲームの開始時に砲弾オブジェクトのプールを作成し、必要に応じて再利用できます。

### オブジェクトプールの作成##creating-an-object-pool

Unity の [`ObjectPool<T>`](/engine/6000.0/script-reference/unityengine/pool/objectpool1.md) クラスは、再利用可能なオブジェクトプールパターンの実装を提供し、アプリケーションにオブジェクトプールを実装する最も簡単な方法です。`ObjectPool<T>` のインスタンスは、`T` 型のオブジェクトのプールを管理します。[`ObjectPool<T>`コンストラクタ](/engine/6000.0/script-reference/unityengine/pool/objectpool1/ctor.md)を使用して`ObjectPool<T>`を作成する場合は、プールの以下のキーを定義するためのパラメーターを指定します。

* プールの開始容量。

* プールを拡張できる最大容量。

* 同じオブジェクト インスタンスをプールに二重解放しないようにコレクションの安全性チェックを実行するかどうか。

* 一連の C# [`Action<T>`](https://learn.microsoft.com/en-us/dotnet/api/system.action-1?view=net-10.0)デリゲート。Unity がプールで以下のキーアクションを実行するときに呼び出すコールバックです。

  * プールからオブジェクトを取得するときに呼び出すコールバックバック
  * オブジェクトをプールに返すときに呼び出すコールバックバック
  * 新しいオブジェクトインスタンスがリクエストされ、プールが空の場合に、インスタンスの作成時に呼び出されるコールバック
  * オブジェクトインスタンスを破棄するときに呼び出されるコールバック

### プールからのオブジェクトの取得##retrieving-objects-from-the-pool

[`ObjectPool<T>.Get`](ScriptRef:ScriptRef:Pool.ObjectPool_1.Get) を呼び出してプールからオブジェクトを取得します。このアクションでは、`ObjectPool`コンストラクタに `actionOnGet` パラメーターとして指定したメソッドも起動します。これにより、使用するオブジェクトを準備してアクティブ化できます。

プールが空のときにプールからオブジェクトをリクエストすると、新しいオブジェクトインスタンスが作成されます。作成プロセスは、`ObjectPool`コンストラクターに`createFunc`パラメーターとして指定したメソッドを呼び出します。

`ObjectPool<T>.Get` には過負荷`Get(out PooledObject<T> pooledObject)`があります。`PooledObject`が破棄されると、インスタンスは自動的に解放されます。これは短命のスコープに役立ちます。

詳細とコード例については、[`PooledObject<T>.Get` API リファレンス](ScriptRef:Pool.PooledObject_1.Get) を参照してください。

### プールへのオブジェクトの返却##returning-objects-to-the-pool

終了したオブジェクトは、プールに返します。引数として返すオブジェクトとともに [`ObjectPool<T>.Release`](/engine/6000.0/script-reference/unityengine/pool/objectpool1/release.md) を呼び出します。このアクションでは、`ObjectPool`コンストラクタに `actionOnRelease` パラメーターとして指定したメソッドも実行されます。このメソッドは、返されたオブジェクトの非アクティブ化とステートのリセットを可能にします。

プールがいっぱいになったときにオブジェクトをプールに戻すと、オブジェクトは破棄されます。破棄プロセスは、`ObjectPool`コンストラクタに`actionOnDestroy`パラメーターとして指定したメソッドを呼び出します。

コンストラクターに`collectionCheck`パラメーターとして`true`を渡すと、コレクションの安全性チェックが有効になります。コレクション チェックが有効になっているときに、すでにプールにあるオブジェクトを返そうとした場合、Unity は例外をスローします。有効にした場合でも、コレクションの確認はエディターでのみ可能で、プレイヤービルドでは使用できません。コレクション チェックを有効にするとオーバーヘッドが増えますが、ダブル リリース エラーがキャッチされるため、開発時に使用することをお勧めします。

### 使用済みオブジェクトをリセットする##resetting-used-objects

プールから取得したオブジェクトは、使用中にステートを変更できます。例えば、プールされた敵ゲームオブジェクトは、シーン内でアクティブなときに、その位置、体力、アニメーションステート、物理演算ステートを変更できます。オブジェクトがプールに返されたときにこのステートをリセットすることが重要です。そうすることで、後で再度取得したときに、最初に使用したのと同じステートで開始されます。

リセットするステートに応じて、`actionOnGet` デリゲートのプールからオブジェクトを取得したとき、または`actionOnRelease` デリゲートのプールにリリースして戻すときに、オブジェクトのリセットを選択できます。プールされたオブジェクト自体にカスタムの非アクティブ化メソッドを実装し、プールの取得またはリリースアクションからそれらのメソッドをコールこともオプションます。

リセットが必要なステートは、プールされたオブジェクトの特定の動作とコンポーネントによって異なります。リリース時の一般的なリセットタスクには、コルーチンの停止、イベントのサブスクライブ解除、物理演算状態のリセット、アニメーションのクリア、パーティクルシステムの停止などがあります。リリース時に GameObjects を非アクティブにして、プールで非アクティブの間[に`Update`](/engine/6000.0/script-reference/unityengine/monobehaviour/update.md)呼び出しを受けないようにすることも重要です。

### 例: 砲弾のプール##example:-pooling-projectiles

砲弾用の`ObjectPool<T>`の一般的な実装には、以下のキーステージがあります。

1. ゲームの開始時に非アクティブの砲弾オブジェクトのプールを作成します。プールされたオブジェクトの新規作成、プールからのオブジェクトの取得、プールへのオブジェクトの解放、プールが満杯になったオブジェクトの破棄時にコールバックとして呼び出すために必要なデリゲートをコンストラクターに提供します。
2. 発射物が必要な場合 (例えば、ユーザーが武器を発射する場合)、`ObjectPool<T>.Get`を使用してプールから非アクティブの発射物を取得します。対応する `actionOnGet` コールバックから、取得したオブジェクトをアクティブ化し、位置や向きなどの関連プロパティを初期化します。
3. 砲弾が不要になったとき (例えば、ターゲットに当たったとき、または範囲外になったとき)、`ObjectPool<T>.Release`とともにプールに戻します。発射体には専用のプールへのリファレンスを渡すのが一般的です。そうすることで、発射後に自身をリリースできます。対応する `actionOnRelease` コールバックから、返されたオブジェクトを非アクティブにし、速度やアニメーションステートなどの関連プロパティをリセットします。

以下のコードは、`ObjectPool<T>`にプールされた砲弾のスクリプトコンポーネントコードです。砲弾には、それ自体のプールへのリファレンスを与える public プロパティがあります。このプロパティは、時間遅延後に自身をプールにリリースするために使用されます。

```cs
using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Pool;
    public class RevisedProjectile :MonoBehaviour
    {
        // Deactivate after delay
        [SerializeField] private float timeoutDelay = 3f;

        private IObjectPool<RevisedProjectile> objectPool;

        // Public property to give the projectile a reference to its ObjectPool
        public IObjectPool<RevisedProjectile> ObjectPool { set => objectPool = value; }

        public void Deactivate()
        {
            StartCoroutine(DeactivateRoutine(timeoutDelay));
        }

        IEnumerator DeactivateRoutine(float 遅延)
        {
            yield return new WaitForSeconds(遅延);

            // Reset the moving Rigidbody
            Rigidbody rBody = GetComponent<Rigidbody>();
            rBody.linearVelocity = new Vector3(0f, 0f, 0f);
            rBody.angularVelocity = new Vector3(0f, 0f, 0f);

            // Release the projectile back to the pool
            objectPool.Release(this);
        }
    }
```

以下のコードは、砲塔にアタッチされたコンポーネントのコードで、砲弾の発射と砲弾オブジェクトのプールの管理を行います。ユーザーが射撃したときに、オブジェクトプールの`Get`が呼び出され、プールされた砲弾が取得されます。

```cs
using UnityEngine;
    using UnityEngine.Pool;
    using UnityEngine.Events;

    public class RevisedGun :MonoBehaviour
    {
        [Tooltip("撃つプレハブ )
        [SerializeField] private RevisedProjectile projectilePrefab;
        [ツールチップ("発射力")]
        [SerializeField] private float muzzleVelocity = 1500f;
        [ツールチップ("ショットが表示される銃の終了位置")]
        [SerializeField] private Transform muzzlePosition;
        [Tooltip("射撃間隔 / 小さい = 発射率が高い")]
        [SerializeField] private float cooldownWindow = 0.1f;

        [SerializeField] private UnityEvent m_GunFired;

        // Stack-based ObjectPool available with Unity 2021 and above
        private IObjectPool<RevisedProjectile> objectPool;

        // Throw an exception if we try to return an existing item, already in the pool
        [SerializeField] private bool collectionCheck = true;

        // Extra options to control the pool capacity and maximum size
        [SerializeField] private int defaultCapacity = 20;
        [SerializeField] private int maxSize = 100;

        private float nextTimeToShoot;

        private void Awake()
        {
            objectPool = new ObjectPool<RevisedProjectile>(CreateProjectile,
                OnGetFromPool, OnReleaseToPool, OnDestroyPooledObject,
                collectionCheck, defaultCapacity, maxSize);
        }

        // Invoked when creating an item to populate the object pool
        private RevisedProjectile CreateProjectile()
        {
            RevisedProjectile projectileInstance = Instantiate(projectilePrefab);
            projectileInstance.ObjectPool = objectPool;
            return projectileInstance;
        }

        // Invoked when returning an item to the object pool
        private void OnReleaseToPool(RevisedProjectile pooledObject)
        {
            pooledObject.gameObject.SetActive(false);
        }

        // Invoked when retrieving the next item from the object pool
        private void OnGetFromPool(RevisedProjectile pooledObject)
        {
            pooledObject.gameObject.SetActive(true);
        }

        // Invoked when the maximum number of pooled items is exceeded (i.e. destroy the pooled object)
        private void OnDestroyPooledObject(RevisedProjectile pooledObject)
        {
            Destroy(pooledObject.gameObject);
        }

        private void FixedUpdate()
        {
            // Invokes the Shoot method if the delay time is exceeded
            if (Input.GetButton("Fire1") && Time.time > nextTimeToShoot && objectPool != null)
            {
                Shoot();
            }
        }

        private void Shoot()
        {
            // Get a pooled object instead of instantiating
            RevisedProjectile bulletObject = objectPool.Get();

            if (bulletObject == null)
                return;

            // Align to gun barrel/muzzle position
            bulletObject.transform.SetPositionAndRotation(muzzlePosition.position, muzzlePosition.rotation);

            // Move projectile forward
            bulletObject.GetComponent<Rigidbody>().AddForce(bulletObject.Transform.フォワード * muzzleVelocity, ForceMode.Acceleration);

            // Turn off after a few seconds
            bulletObject.Deactivate();

            // Set cooldown delay
            nextTimeToShoot = Time.time + cooldownWindow;

            m_GunFired.Invoke();
        }
    }
```

このコードを使用した完全なサンプルプロジェクトは、必要なすべてのプレハブとプールされた砲弾を発射する作業用タレットを含めて、[アセットストア](https://assetstore.unity.com/packages/essentials/tutorial-projects/level-up-your-code-with-design-patterns-and-solid-289616))から無料のパッケージとしてダウンロードできます。詳細については、『 [オブジェクトプール使用](https://learn.unity.com/course/design-patterns-unity-6/tutorial/use-object-pooling-to-boost-performance-of-c-scripts-in-unity#67a0d722edbc2a14cfcb7400)による Unity での C# スクリプトのパフォーマンス向上 』を参照してください。

### プールされたオブジェクトのシーンアンロードの処理##handling-scene-unload-for-pooled-objects

デフォルトでは、オブジェクトプールは作成されたシーンに関連付けられています。そのシーンがアンロードされると、Unity はそのシーン内のすべての GameObjects (プールとプールされたインスタンスを含む) を破棄します。

シーンのリロード後にオブジェクトプールを維持するには、[`object.DontDestroyOnLoad`](/engine/6000.0/script-reference/unityengine/object/dontdestroyonload.md) を呼び出すルートゲームオブジェクトの下にプールマネージャーを配置します。[`transform.SetParent` を](/engine/6000.0/script-reference/unityengine/transform/setparent.md)呼び出すと、プールルートの下にプールされた項目をリリース時に親にして、シーンで破棄しないようにすることができます。

アンロード時にシーン内にプールされたアクティブなインスタンスがある場合は、それら[が`OnDisable`](/engine/6000.0/script-reference/unityengine/monobehaviour/ondisable.md)と[`OnDestroy`](/engine/6000.0/script-reference/unityengine/monobehaviour/ondestroy.md)でリリースされているか、アイテムを呼び出すか破棄する[`SceneManager.activeSceneChanged`](/engine/6000.0/script-reference/unityengine/scenemanagement/scenemanager/activescenechanged.md)コールバックが登録されていることを確認してください。

非アクティブの場合、プールされたインスタンスへの長期参照を避けます。[`ObjectPool<T>.Clear`](/engine/6000.0/script-reference/unityengine/pool/objectpool1/clear.md) を使用して、例えばレベル間で非アクティブなインスタンスをすべて破棄します。

## コレクションタイプのプーリングと再利用##pooling-and-reusing-collection-types

また、Lists や Dictionaries など、[`System.Collection`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic?view=net-6.0) 名前空間から収集オブジェクトをプールして再利用することもできます。

コレクションクラスは、コレクションの値を削除しますが、コレクションに割り当てられたメモリはリリースしない `Clear` メソッドを公開します。これは複雑な計算のために一時的なヘルパーCollectionsを割り当てたい場合に便利です。

以下のコード例では、フレームごとに 1 回`nearestNeighbors` `List`を割り当てて、一連のデータ ポイントを収集しています。これは非効率な実践方法です。

```lang-cs
// Bad C# script example. This Update method allocates a new `List` every frame.
void Update() {

    List<float> nearestNeighbors = new List<float>();

    findDistancesToNearestNeighbors(nearestNeighbors);

    nearestNeighbors.Sort();

    // … use the sorted list somehow …
}
```

代わりに、この`List`をメソッドの外、包含するクラスに持ち上げ、そのたびに消去して再利用できます。これにより、コードがフレームごとに新しい`List`を割り当てる必要がなくなります。

```lang-cs
// Good C# script example. This method re-uses the same List every frame.
List<float> m_NearestNeighbors = new List<float>();

void Update() {

    m_NearestNeighbors.Clear();

    findDistancesToNearestNeighbors(NearestNeighbors);

    m_NearestNeighbors.Sort();

    // … use the sorted list somehow …
}
```

このサンプル コードでは、`List`インスタンスのメモリを複数のフレームで保持して再利用しています。コードは、`List`の拡張が必要なときのみ新しいメモリーを割り当てます。

`UnityEngine.Pool`名前空間では、`List<T>`、`HashSet<T>`、`Dictionary<TKey, TValue>`などのいくつかのコレクション タイプ向けに既製のプール実装も提供されます。これらは `ObjectPool<T>` と同じ原理で動作し、プールされたコレクションオブジェクトインスタンスを必要に応じて取得およびリリースできます。詳細と例については、[`CollectionPool<T>`](ScriptRef:Pool.CollectionPool_1) および同じ名前空間の他のコレクション タイプ固有のプール クラスに関する API リファレンス ドキュメントを参照してください。

## 追加リソース##additional-resources

* [チュートリアルの学習:オブジェクトプールを使用してUnity](https://learn.unity.com/course/design-patterns-unity-6/tutorial/use-object-pooling-to-boost-performance-of-c-scripts-in-unity#67a0d722edbc2a14cfcb7400)のC#スクリプトのパフォーマンスを向上
* [マネージメモリの概要](/engine/6000.0/manual/analysis/performance-memory/managed-memory/introduction.md)
* [リファレンスタイプの管理](/engine/6000.0/manual/scripting/optimization/performance-optimizing-code-managed-memory/reference-types.md)
* [アレイの最適化](/engine/6000.0/manual/scripting/optimization/performance-optimizing-code-managed-memory/arrays.md)
* [砲弾と爆発](/engine/6000.0/manual/working-with-gameobjects/prefabs/instantiating/projectiles.md)のインスタンス化。
