Object Pool System
The Problem: Continuous Instantiate/Destroy Causes GC Spikes
In a tower defense game, hundreds of projectiles and dozens of enemies are constantly created and destroyed. Repeatedly calling Instantiate() and Destroy() causes Garbage Collection spikes — particularly dangerous on mobile, leading to frame stutters.
The Solution: Object Pooling
Instead of creating and destroying, the system reuses pre-created GameObjects:
// PoolManager.cs
public void Prewarm(GameObject prefab, int count)
{
if (!_pools.ContainsKey(prefab))
_pools[prefab] = new Queue<GameObject>();
for (int i = 0; i < count; i++)
{
var obj = Instantiate(prefab);
obj.SetActive(false);
_pools[prefab].Enqueue(obj);
}
}
public GameObject GetFromPool(GameObject prefab)
{
if (_pools.TryGetValue(prefab, out var pool) && pool.Count > 0)
{
var obj = pool.Dequeue();
obj.SetActive(true);
return obj;
}
return Instantiate(prefab); // Fallback if pool is empty
}
public void ReturnPool(GameObject prefab, GameObject obj)
{
obj.SetActive(false);
_pools[prefab].Enqueue(obj);
}
Actual Flow
- At game load (
Awake): Pre-warm 3 instances per tower and projectile type into the pool - When firing:
TowerViewcallsPoolManager.GetFromPool(bulletPrefab)instead ofInstantiate - When projectile hits: Calls
PoolManager.ReturnPool(bulletPrefab, bullet)instead ofDestroy
Result: No new allocations in the game loop — the GC is never triggered by projectile or enemy creation/destruction.