Yazılarımız

Veri Akademi

UNİTY İLE PERFORMANS PROFİLİNG YAPMAK VE FPS STABİL TUTMAK

Oyuncu “takılma” hissettiğinde çoğu zaman ortada tek bir büyük sorun değil, biriken küçük maliyetlerin yarattığı düzensiz kare süreleri vardır. Bu yüzden hedef sadece yüksek FPS almak değil, kare sürelerini tutarlı hâle getirmek, yani oynanışı akıcı tutmaktır.

Unity ile performans profiling yapmak, hangi sistemin “fazla zaman yediğini” somut verilerle görmenizi sağlar: CPU mu, GPU mu, bellek tahsisi mi, fizik mi, yoksa sahnedeki çizim (render) işi mi? Bu yazıda, Profiler verisini doğru okumayı ve FPS’i stabil tutmak için en çok işe yarayan optimizasyon adımlarını ele alacağız.

Adımları uygularken, en büyük kazanımı genellikle “ölçmek → hipotez kurmak → küçük bir değişiklik yapmak → tekrar ölçmek” döngüsünün getirdiğini göreceksiniz. Eğer ekip içinde ortak bir dil oluşturmak ve pratiklerle kalıcı bir süreç oturtmak istiyorsanız, Unity eğitimi sayfasındaki içeriklere de göz atabilirsiniz.

Unity Profiler ekranında CPU ve GPU zamanlamalarıyla kare süresi dalgalanmasını karşılaştıran analiz görünümü

Performans Profiling Mantığını Netleştirmek ve Ölçmek

FPS yerine kare süresi okumayı alışkanlık hâline getirmek

FPS tek başına yanıltıcı olabilir. 60 FPS hedefinde ideal kare süresi yaklaşık 16.67 ms iken, 30 FPS için yaklaşık 33.33 ms beklenir. Oyuncunun hissettiği “stutter” çoğu zaman ortalama FPS’ten değil, kare sürelerinin bir anda zıplamasından kaynaklanır. Bu nedenle önce kare sürelerini (ms) takip etmek, sonra FPS’i yorumlamak daha sağlıklıdır.

Ölçümü aynı koşullarda tekrarlamak ve kıyaslamak

Profiling sırasında “aynı sahne, aynı kamera, aynı içerik, aynı kalite ayarı” ile tekrar ölçmek kritik olur. Arada çözünürlük, VSync, kalite profili, gölge mesafesi veya farklı build ayarı değişirse, sonuçlar karşılaştırılamaz. Karar vermeyi kolaylaştırmak için tek bir test senaryosu tanımlamak, ekip içi iletişimi de hızlandırır.

Unity Profiler Kurulumu Doğru Yapmak ve Yanıltıcı Veriden Kaçınmak

Editor ile cihaz ölçümünü ayırmak ve build üzerinden doğrulamak

Editor içindeki ölçümler genellikle gerçeğe yakın bir fikir verse de, editor overhead’i nedeniyle CPU tarafında maliyetler şişebilir. Bu yüzden ilk analizleri editor’da yapıp, kritik kararları mutlaka build üzerinde doğrulamak gerekir. Mobil veya konsol hedefliyorsanız, test cihazında ölçüm almak çok daha güvenilir olur.

Development Build ve Autoconnect Profiler ile pratik izleme yapmak

İlk tespitte Development Build açıp Profiler’ı otomatik bağlamak, problemi hızlı yakalamanızı sağlar. Ancak Development Build ek yük getirebilir; bu yüzden iyileştirme sonrası son doğrulamada daha gerçekçi ayarlarla ölçüm yapmak önemlidir. Hedefiniz “sorunu bulmak” ile “nihai performansı onaylamak” süreçlerini ayrı düşünmek olmalıdır.

Sahne görünümünde gölge mesafesi ve ışık sayısı azaltılarak GPU yükünün düşürüldüğü bir oyun ortamı

CPU ve GPU Darboğazını Ayırt Etmek ve Stabil Tutmak

Önce darboğazın kimde olduğunu belirlemek

Stabil FPS için en temel soru şudur: CPU mu sınırlıyor, GPU mu? Profiler’da ana thread süreleri yüksekse CPU darboğazı, GPU zamanı baskınsa GPU darboğazı düşünülür. Ayrıca render thread, job worker thread’ler ve “WaitForTargetFPS” gibi beklemeler de doğru yorumlanmalıdır. Örneğin VSync açıksa CPU, GPU’nun yetişmesini bekliyor gibi görünebilir; bu durumda darboğazı yanlış teşhis edebilirsiniz.

Kare süresi dalgalanmasının kök nedenini izole etmek

FPS’in bazen düşmesi yerine sürekli “iniş çıkış” yapması, genellikle şu üç kaynaktan gelir: (1) periyodik iş (garbage collection, asset streaming, ışık bake önbelleği vb.), (2) sahneye bağlı “burst” maliyetler (çok sayıda Instantiate/Destroy, partikül patlaması), (3) kamera/LOD/occlusion gibi sistemlerin anlık yük değişimi. Bu üç kaynağı tek tek izole ederek test etmek, problemi kalıcı biçimde çözmeye yardım eder.

GC, Bellek Tahsisi ve Spike Sorunlarını Azaltmak

Allocation’ları takip etmek ve gereksiz tahsisleri engellemek

“GC Alloc” kolonunda gördüğünüz tahsisler, kısa vadede FPS’i düşürmeyebilir; fakat birikince GC tetiklenir ve ani spike üretir. Özellikle Update içinde string birleştirme, LINQ, boxing, sık instantiate edilen geçici listeler ve gereksiz ToArray çağrıları tahsisi artırır. Kodda küçük düzenlemelerle tahsisleri azaltmak, akıcılığı belirgin şekilde artırır.

Object pooling yaklaşımını sistematikleştirmek ve standardize etmek

Sürekli Instantiate/Destroy yapmak hem CPU’da maliyet yaratır, hem de bellek tarafında baskı oluşturur. Pooling, özellikle mermi, düşman, UI öğesi ve partikül gibi sık doğup ölen objelerde büyük fayda sağlar. Aşağıdaki örnek, basit bir pooling yaklaşımını göstermektedir:

using System.Collections.Generic;
using UnityEngine;

public class SimplePool : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    [SerializeField] private int warmupCount = 32;

    private readonly Queue<GameObject> pool = new Queue<GameObject>();

    void Awake()
    {
        for (int i = 0; i < warmupCount; i++)
        {
            var go = Instantiate(prefab);
            go.SetActive(false);
            pool.Enqueue(go);
        }
    }

    public GameObject Get(Vector3 pos, Quaternion rot)
    {
        GameObject go = pool.Count > 0 ? pool.Dequeue() : Instantiate(prefab);
        go.transform.SetPositionAndRotation(pos, rot);
        go.SetActive(true);
        return go;
    }

    public void Release(GameObject go)
    {
        go.SetActive(false);
        pool.Enqueue(go);
    }
}

Bu yapıyı ekip standardı hâline getirmek, herkesin farklı pooling mantığı yazmasını engeller. Böylece sahneler arası davranış tutarlı kalır ve profiling çıktılarında yorumlama kolaylaşır.

Render Maliyetlerini Düşürmek ve GPU Tarafını Rahatlatmak

Draw call, setpass ve overdraw’ı azaltmak

GPU tarafında en sık karşılaşılan problemler; fazla draw call, pahalı shader’lar, yüksek overdraw ve gereksiz post-process maliyetleridir. İlk adım olarak, sahnede gereksiz materyal çeşitliliğini azaltmak ve mümkün olduğunda batching/instancing avantajı sağlayacak şekilde varlıkları düzenlemek işe yarar. Transparan materyaller overdraw’ı artırır; UI ve partikül yoğun sahnelerde bu etki daha da büyür.

Kalite ayarlarını hedef platforma göre kademelendirmek

Gölge çözünürlüğü, shadow distance, anti-aliasing, SSAO, bloom gibi efektler GPU yükünü hızlı artırır. Buradaki strateji, tek bir “en iyi kalite” yerine farklı cihaz seviyeleri için kademeli profil oluşturmak olmalıdır. Örneğin düşük/orta/yüksek profillerle, aynı sahnede GPU zamanını ölçüp hedeflediğiniz kare süresine yaklaşacak şekilde ayarları basamaklandırabilirsiniz.

Performans ölçümünde özel profiler marker çizgileriyle fonksiyon sürelerinin zamana göre izlenmesi

Özel Profiler Marker Eklemek ve Sorunlu Noktayı Hızla Bulmak

Unity.Profiling ile ölçülebilir bölgeler tanımlamak

Profiler’da bazen “Script” altında kalabalık bir liste görürsünüz ama hangi fonksiyonun neden pahalı olduğunu anlamak zorlaşır. Bu durumda, kritik kod yollarına marker eklemek, ekibin aynı noktaya bakmasını sağlar. Aşağıdaki örnek, belirli bir hesaplama bloğunu işaretlemek için kullanılabilir:

using Unity.Profiling;
using UnityEngine;

public class DamageSystem : MonoBehaviour
{
    static readonly ProfilerMarker ApplyDamageMarker =
        new ProfilerMarker("DamageSystem.ApplyDamage");

    public void ApplyDamage(GameObject target, int amount)
    {
        ApplyDamageMarker.Begin();

        // Simulated work
        var health = target.GetComponent<Health>();
        if (health != null)
        {
            health.Value -= amount;
        }

        ApplyDamageMarker.End();
    }
}

Marker’lar sayesinde “hangi çağrı ne kadar sürüyor” sorusu daha net cevaplanır. Ayrıca değişiklik yaptıktan sonra aynı marker üzerinden kıyaslayarak ilerlemek, optimizasyon kararlarını veriyle destekler.

Derin ölçümü sınırlamak ve yanlış alarmları azaltmak

Deep profiling veya aşırı ayrıntılı ölçüm, analiz sırasında yardımcı olsa da performansı ciddi etkileyebilir. Bu yüzden sorunlu bölgeyi bulduktan sonra ölçümü daraltmak ve sadece ilgili marker’lar üzerinden ilerlemek daha verimli olur. Amaç “her şeyi görmek” değil, asıl maliyeti yaratan yolu kısa sürede ortaya çıkarmaktır.

Pratik Stabilizasyon Kontrol Listesi Oluşturmak ve Süreçleştirmek

Değişiklikleri küçük tutmak ve etkisini hemen doğrulamak

Bir anda 10 farklı ayarı değiştirmek, hangi değişikliğin fayda sağladığını belirsiz kılar. Bunun yerine küçük, izlenebilir adımlar atmak gerekir. Aşağıdaki liste, günlük akışta pratik bir kontrol yaklaşımı sunar:

  • Ölçüm senaryosunu sabitlemek ve aynı koşullarda test etmek
  • Darboğazı CPU/GPU olarak ayırmak, sonra alt kırılımı incelemek
  • GC Alloc kaynaklarını tespit etmek ve Update içindeki tahsisleri azaltmak
  • Instantiate/Destroy yoğun noktaları pooling ile dönüştürmek
  • Gölge/efekt ayarlarını hedef cihaza göre kademelendirmek
  • Marker ekleyerek kritik fonksiyonları kıyaslanabilir hâle getirmek

Sahne ve içerik üretimini performans hedefleriyle uyumlu tutmak

Stabil FPS, sadece programlama tarafında değil, içerik üretiminde de hedeflenmelidir. Model yoğunluğu, kaplama boyutları, shader karmaşıklığı ve ışık sayısı gibi kararlar, oyun daha baştan “pahalı” mı “verimli” mi olacak sorusunu belirler. Tasarım ve teknik ekip arasında ortak performans hedefi koymak, sonradan yapılan pahalı düzeltmeleri azaltır.


Sonuç olarak Unity ile performans profiling yapmak, “tahmin” yerine “ölçüm” üzerinden ilerlemenizi sağlar. Doğru kurulum, doğru yorum ve küçük ama etkili değişikliklerle kare sürelerini dengede tutabilir, böylece FPS’in farklı cihazlarda daha stabil kalmasını sağlayabilirsiniz.

 ANİMASYON AKADEMİ