🎮 UnityDocs

Object Pooling: reciclar en vez de crear

Por qué crear y destruir objetos sin parar provoca tirones, y cómo un pool reutiliza objetos para evitarlo. Con la clase ObjectPool integrada en Unity 6 y un ejemplo de balas.

📄 ArtículoAvanzado✅ RevisadoUnity 6.0 LTSActualizado 2026-07-15
DificultadConceptual Código Matemáticas
Tiempo📖 Lectura 8 min · ⌨️ Práctica 25 min

El problema#

Cada vez que haces Instantiate, Unity reserva memoria; cada Destroy deja "basura" que el recolector (GC) tendrá que limpiar más tarde. Cuando esto pasa constantemente (balas, casquillos, impactos, partículas, enemigos que reaparecen), el GC salta a destiempo y provoca tirones (frame drops). Además, crear y destruir repite trabajo que podríamos ahorrarnos.

🎬 Por dentro · Qué es un 'GC spike'

El recolector de basura de .NET libera de golpe la memoria de los objetos que ya nadie usa. Si generas mucha basura, esas limpiezas son más largas y frecuentes, y cada una puede "comerse" varios milisegundos de un fotograma, justo lo que se percibe como un micro-tirón. El pooling ataca la causa: si no creas basura, el GC no tiene que limpiarla.

La idea del pooling#

En vez de crear y destruir, creas un conjunto de objetos una vez y los reutilizas: cuando necesitas una bala, coges una "dormida" del pool y la activas; cuando termina, la desactivas y la devuelves al pool en lugar de destruirla.

⚖️ Comparativa · Instantiate/Destroy vs Object Pool
Instantiate + DestroyObject Pool
Memoria en runtimeReserva y libera constantementeReutiliza la misma
Basura para el GCMuchaCasi ninguna
Coste por objetoCrear + destruir cada vezActivar/desactivar
Ideal paraObjetos rarosObjetos muy frecuentes

El ObjectPool de Unity 6#

No hace falta escribir el pool a mano: Unity incluye ObjectPool<T> en UnityEngine.Pool.

C#
using UnityEngine;
using UnityEngine.Pool;

public class PoolBalas : MonoBehaviour
{
    [SerializeField] private Bala balaPrefab;
    private IObjectPool<Bala> pool;

    void Awake()
    {
        pool = new ObjectPool<Bala>(
            createFunc: () => {
                Bala b = Instantiate(balaPrefab);
                b.SetPool(pool);            // la bala sabe a qué pool volver
                return b;
            },
            actionOnGet: b => b.gameObject.SetActive(true),
            actionOnRelease: b => b.gameObject.SetActive(false),
            actionOnDestroy: b => Destroy(b.gameObject),
            defaultCapacity: 30,
            maxSize: 100
        );
    }

    public Bala Pedir() => pool.Get();          // en vez de Instantiate
}

Y la bala se devuelve sola al terminar (al salir de pantalla o tras un tiempo):

C#
using UnityEngine;
using UnityEngine.Pool;

public class Bala : MonoBehaviour
{
    private IObjectPool<Bala> pool;
    public void SetPool(IObjectPool<Bala> p) => pool = p;

    void OnEnable() => Invoke(nameof(Devolver), 3f);   // vida de 3 s

    void Devolver()
    {
        CancelInvoke();
        pool.Release(this);      // en vez de Destroy
    }
}

Cuándo NO usar pooling#

No lo metas en todo

El pooling añade complejidad: hay que resetear el estado del objeto al reutilizarlo (posición, velocidad, vida...). Para objetos que aparecen una vez o rara vez, Instantiate/Destroy normal es más simple y suficiente. Reserva el pooling para lo que se crea muchísimo. Y antes de optimizar, mide con el Profiler: quizá tu cuello de botella esté en otro sitio.

Errores frecuentes#

  • Olvidar resetear el estado al reutilizar (una bala vuelve con la velocidad de la anterior).
  • No devolver los objetos al pool (se quedan "en uso" y el pool crea de más).
  • Poolear objetos raros y complicar el código sin ganancia.
  • Optimizar por intuición sin medir antes.

Ponte a prueba#

📝 Pon a prueba lo aprendido

Resumen#

Crear y destruir objetos sin parar genera basura y tirones. El object pooling reutiliza un conjunto fijo activando/desactivando en vez de Instantiate/Destroy. Unity 6 trae ObjectPool<T> listo para usar. Aplícalo a lo que se crea muchísimo (balas, partículas), resetea siempre el estado al reutilizar y mide con el Profiler antes de optimizar.

Fuentes y para profundizar