Merhaba arkadaşlar!
Unity’de oyun geliştirirken en sevdiğimiz kısayollardan biri şudur: ihtiyacın olunca Instantiate, işin bitince Destroy. Mermi attın, düşman spawn ettin, patlama efekti oynadın — her şey çalışıyor gibi görünür.
Ta ki oyun biraz büyüyene kadar.
Özellikle hyper-casual, match-3, shooter veya aynı anda çok obje üreten oyunlarda bu yaklaşım yavaş yavaş can sıkmaya başlar. FPS düşer, mikro takılmalar olur, Profiler’da GC Alloc satırları kırmızıya boyanır.
Bugün bu sorunun pratik bir çözümünü konuşacağız: Object Pooling.
Korkmayın — karmaşık bir mimari değil. Bir prefab’ı bir kez oluşturup tekrar tekrar kullanmak. Bu kadar.
Instantiate / Destroy Neden Sorun Olur?
Unity’de Instantiate ve Destroy çağırdığınızda arka planda şunlar olur:
- Yeni obje heap üzerinde oluşturulur
Destroyobjeyi hemen silmez; işaretleme yapar- Biriken objeler Garbage Collection (GC) ile temizlenir
- GC çalışırken ana thread kısa süre durabilir → frame spike
Tek bir mermi için sorun değildir. Ama şu senaryoyu düşünün:
mermi/sn
5
düşman spawn
1
patlama/isabet
Bu, saniyede onlarca allocation demek. Mobil cihazda oyuncu bunu “oyun takılıyor” diye hisseder.

Hatırlatma: DOTween vs PrimeTween yazısında da benzer mantığı konuşmuştuk — çok sayıda küçük maliyet birikince performans bozulur.
Object Pooling Nedir?
Object Pooling, önceden belirli sayıda obje oluşturup bunları bir havuzda tutmaktır. İhtiyaç olunca havuzdan alır, işin bitince geri verirsin.

Bu sayede runtime’da sürekli Instantiate/Destroy döngüsünden kurtulursun.
Basit Bir Pool Sınıfı
Aşağıdaki generic pool sınıfı birçok projede işinizi görür — mermi, düşman, efekt…
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool<T> where T : Component
{
private readonly T _prefab;
private readonly Transform _parent;
private readonly Queue<T> _pool = new();
public ObjectPool(T prefab, int initialSize, Transform parent = null)
{
_prefab = prefab;
_parent = parent;
for (int i = 0; i < initialSize; i++)
{
T instance = Object.Instantiate(_prefab, _parent);
instance.gameObject.SetActive(false);
_pool.Enqueue(instance);
}
}
public T Get(Vector3 position, Quaternion rotation)
{
T instance = _pool.Count > 0 ? _pool.Dequeue() : Object.Instantiate(_prefab, _parent);
instance.transform.SetPositionAndRotation(position, rotation);
instance.gameObject.SetActive(true);
return instance;
}
public void Release(T instance)
{
instance.gameObject.SetActive(false);
_pool.Enqueue(instance);
}
}Ne yaptık?
initialSizekadar obje önceden oluşturulduGet→ havuzdan alRelease→ geri ver, Destroy yok
Örnek 1: Mermi Pool’u
BulletSpawner.cs
public void Fire()
{
Bullet bullet = _bulletPool.Get(_firePoint.position, _firePoint.rotation);
bullet.Initialize(_bulletPool);
}Bullet.cs — süre dolunca veya çarpınca:
_pool.Release(this); // Destroy değil!
Örnek 2: Düşman Pool’u
Düşman öldüğünde: _pool.Release(this); — sahne sayısı sabit kalır.
Örnek 3: VFX / Patlama Efekti
Particle System bitince coroutine ile Release — her patlamada yeni prefab yok.
Ne Zaman Pool Kullanmalısın?
| Durum | Pool? |
|---|---|
| Sık spawn/destroy (mermi, düşman, efekt) | ✓ Evet |
| Mobil / hyper-casual / yoğun gameplay | ✓ Evet |
| Profiler’da GC spike görüyorsan | ✓ Evet |
| Saniyede 5+ kez aynı prefab | ✓ Evet |
| Ana menüde bir kez açılan popup | ✗ Hayır |
| Sahne geçişinde bir kez yüklenen obje | ✗ Hayır |
| Toplam 3–5 adet statik obje | ✗ Hayır |
Kural: Kısa ömürlü + sık tekrar → pool. Nadir + uzun süre sahnede → normal Instantiate.
Dikkat Etmen Gereken 4 Şey
- Obje durumunu sıfırla —
OnEnableiçinde health, velocity vb. - Havuz boyutu — Profiler peak kullanımına göre
initialSizeayarla. - Parent Transform — BulletPool, EnemyPool altında topla.
- UnityEngine.Pool — Unity 2021+ hazır API; mantık aynı.
Pool vs Instantiate
| Instantiate / Destroy | Object Pool | |
|---|---|---|
| GC baskısı | Yüksek | Düşük |
| Spawn hızı | Her seferinde allocation | Havuzdan anında |
| Bellek | Dalgalanma | Önceden ayrılmış |
| Mobil oyunlar | Riskli | Önerilir |
Sonuç
Object Pooling, doğru yerde kullanıldığında standart bir alışkanlık.
- Sık spawn →
Instantiate/Destroydöngüsünden kaçın - Profiler’da GC Alloc varsa pool adayı var demektir
- Kısa ömürlü + sık tekrar = pool adayı
Bir kez dene — Profiler farkını görünce geri dönmek istemezsin.





