Summary
Unity performance work comes down to three budgets: CPU frame time, GC allocations, and GPU draw calls. Profiling with the Unity Profiler and Frame Debugger before changing code — rather than guessing — is what separates a stable 60 FPS build from one that stutters under load.
1. Profile Before You Optimize
The Unity Profiler's CPU, GPU, Memory and Rendering modules, plus the Frame Debugger, should be the first stop for any performance investigation — not code intuition.
Deep Profiling & the Frame Debugger: Deep Profiling instruments every managed call for exact allocation counts. The Frame Debugger steps through each draw call in a frame, showing precisely why the GPU did what it did — batched, instanced, or issued as a separate call.
Deep Profiling & the Frame Debugger: Deep Profiling instruments every managed call for exact allocation counts. The Frame Debugger steps through each draw call in a frame, showing precisely why the GPU did what it did — batched, instanced, or issued as a separate call.
2. Garbage Collection & Managed Allocations
Every managed allocation in
Common sources of hidden per-frame allocation:
Update() eventually triggers a GC pass, and GC pauses are one of the most common causes of frame spikes on mobile hardware.
// Object pool instead of Instantiate/Destroy per shot
public class BulletPool : MonoBehaviour {
readonly Queue<GameObject> pool = new();
[SerializeField] GameObject bulletPrefab;
[SerializeField] int prewarm = 64;
void Awake() {
for (int i = 0; i < prewarm; i++) {
var go = Instantiate(bulletPrefab);
go.SetActive(false);
pool.Enqueue(go);
}
}
public GameObject Get() =>
pool.Count > 0 ? pool.Dequeue() : Instantiate(bulletPrefab);
public void Release(GameObject go) {
go.SetActive(false);
pool.Enqueue(go);
}
}GetComponent<T>() called every frame instead of cached in Awake(), LINQ inside Update(), string concatenation for UI text, and boxing value types into object parameters.3. GPU Draw Call Batching
| Technique | How It Reduces Draw Calls | Best For |
|---|---|---|
| Static Batching | Combines non-moving meshes sharing a material into one draw call at build time | Level geometry, props |
| GPU Instancing | Issues one draw call for many copies of the same mesh with per-instance data | Foliage, crowds, particles |
| SRP Batcher | Reduces per-object render-state changes on URP/HDRP without merging meshes | General URP/HDRP scenes |