Bellek Havuzu (Object Pool): Oyunda Nesneleri Verimli Yönetme

Oyunlarda her saniye yüzlerce nesne oluşturup silmek sistem kaynağını boşa harcar. Mermi ateşlediğinde yeni nesne oluşturmak, mermi hedefe ulaştığında silmek, bu işlem tekrar tekrar yapılırsa, bellek parçalanması ve çöp toplayıcı (garbage collector) gecikmesi ortaya çıkar. Bellek havuzu (object pool) bu sorunu çözer: nesneleri önceden oluşturup depolayan ve gerektiğinde geri döngüsel olarak kullanan bir sistem.

Temel Mantık

Havuzda belirli sayıda nesne önceden hazırlanır. Bir nesneye ihtiyaç duyulduğunda havuzdan alınır ve kullanılır. İş bittiğinde silinmez, havuza geri konur. Bu sayede bellek tahsisi bir kez yapılır, sonrasında yalnızca nesne durumu sıfırlanır.

Adım Adım Uygulama

Birinci adım: havuz sınıfı oluşturmak. Mermi için basit bir havuz yazalım.

Reklam · TEST
AdSense Test ReklamıYazı arası (gönderi içi) · Yazı arası
1public class BulletPool
2{
3private Queue<Bullet> availableBullets;
4private List<Bullet> allBullets;
5private int poolSize = 50;
6
7public BulletPool()
8{
9availableBullets = new Queue<Bullet>(poolSize);
10allBullets = new List<Bullet>(poolSize);
11
12for (int i = 0; i < poolSize; i++)
13{
14Bullet bullet = new Bullet();
15bullet.SetActive(false);
16availableBullets.Enqueue(bullet);
17allBullets.Add(bullet);
18}
19}
20
21public Bullet GetBullet(Vector3 position, Vector3 direction)
22{
23Bullet bullet;
24if (availableBullets.Count > 0)
25{
26bullet = availableBullets.Dequeue();
27}
28else
29{
30bullet = new Bullet();
31allBullets.Add(bullet);
32}
33
34bullet.Reset(position, direction);
35bullet.SetActive(true);
36return bullet;
37}
38
39public void ReturnBullet(Bullet bullet)
40{
41bullet.SetActive(false);
42availableBullets.Enqueue(bullet);
43}
44}

İkinci adım: mermi sınıfı havuz ile çalışacak şekilde tasarlamak.

1public class Bullet
2{
3public Vector3 position;
4public Vector3 direction;
5private bool isActive;
6
7public void Reset(Vector3 pos, Vector3 dir)
8{
9position = pos;
10direction = dir.normalized;
11}
12
13public void SetActive(bool active)
14{
15isActive = active;
16}
17
18public bool IsActive() => isActive;
19
20public void Update()
21{
22if (!isActive) return;
23position += direction * 10f * Time.deltaTime;
24}
25}

Üçüncü adım: oyun döngüsünde havuzu kullanmak.

1BulletPool bulletPool = new BulletPool();
2
3void OnShoot(Vector3 pos, Vector3 dir)
4{
5Bullet bullet = bulletPool.GetBullet(pos, dir);
6}
7
8void OnBulletHit(Bullet bullet)
9{
10bulletPool.ReturnBullet(bullet);
11}

Çıktı: İlk karede 50 mermi belleğe alınır. Ateş ettikçe havuzdan çekilir, isabet ettikçe geri konur. Bellek tahsisi artmaz, çöp toplayıcı çalışmaz.

Pratik İpucu

Havuz boyutunu oyunun en yoğun anına göre ayarla. Eğer maksimum 100 mermi aynı anda uçabiliyorsa, havuz boyutu en az 100 olmalı. Havuz boşalırsa, yeni nesne oluşturma maliyeti ortaya çıkar; bu da performans düşüşüne neden olur.

Reklam · TEST
AdSense Test ReklamıGönderi altı · Görüntülü
konu hakkında tepkinizi verebilirsiniz
  • adlı kullanıcıya yanıt verdi
    pazartesiyorgunu

    aynen o yüzden ben sabit tutuyorum ne kadar nesneler gerekliyse baştan hesapla koy havuzda sonra uğraşma

  • adlı kullanıcıya yanıt verdi
    kodkafasi

    dinamik havuz işe yarayabiliyor ama ihtiyaca göre büyüyüp küçülmesi kodlama tarafında daha karışık oluyor

  • adlı kullanıcıya yanıt verdi
    pazartesiyorgunu

    ama havuzun boyutunu yanlış ayarlarsan boku çıkıyor az havuz açarsan yine bellek patlar çok havuz açarsan boşa yer kaplar

  • adlı kullanıcıya yanıt verdi
    kodkafasi

    ya ben de düşündüm hep yeni mermi oluşturmak yerine havuzdan almak çok daha mantıklı ne kadar az bellek sızıntısı oluyor fark ettim

  • pazartesiyorgunu

    Mermi havuzunda bunu uygulamışım fark inanılmaz Başta yüz mermi oluştursam bile sonra hep aynı nesneleri geri döngüyle kullanıyorsun bellek patlamıyor