Eonevolve Learning
Unity and DevelopmentUnity and codeAdvanced~7 min

Unity Mobile 60 FPS: Draw Calls & Zero-GC Budgeting

Snapshot

~90 sec

Shipping 60 FPS on mobile devices requires three strict engineering boundaries: keeping Draw Calls under 100 via GPU Instancing/SRP Batcher, capping frame budget at 16.6ms, and eliminating per-frame Garbage Collection (GC) allocations.

You will learn

  • Master the 16.6ms Mobile Frame Budget breakdown (CPU, GPU, VSync, Thermal Throttling).
  • Combine Draw Calls using SRP Batcher, GPU Instancing, and UI Texture Atlases.
  • Eliminate per-frame heap allocations (LINQ, string concatenation, unpooled lambdas) that cause GC stutter.

Target outcome

You can profile and optimize a stuttering Unity mobile build to run at a rock-solid 60 FPS with zero thermal throttling.

Visual walkthrough

Visual walkthrough

~7 min

  1. Mobile Frame Budget & Performance Limits

    • 16.6ms Total Budget

      For 60 FPS, CPU logic + GPU rendering must complete in under 16.6ms (aim for 12ms to prevent thermal throttling).

    • Draw Call (Batches) Cap

      Target < 80-120 batches per frame on mid-range Android/iOS devices to keep CPU driver overhead low.

    • Zero GC Alloc in Update

      0 B/frame heap allocation during active gameplay. Garbage Collection spikes trigger unavoidable 30-80ms micro-stutters.

    • ASTC Texture Compression

      Always use ASTC 6x6 or 4x4 on mobile to drastically reduce GPU memory bandwidth and battery heat.

  2. Eliminating Common Per-Frame Allocations in C#

    By replacing LINQ, string concatenation, and allocating physics methods with NonAlloc buffers and StringBuilders, per-frame GC allocations drop to exactly 0 Bytes.

    Languagecsharp
    // BAD: Allocates heap memory every single frame
    void BadUpdate() {
        // 1. String concatenation generates a new string object
        scoreText.text = "Score: " + score;
    
        // 2. Non-cached Physics RaycastAlloc / OverlapSphereAlloc
        Collider[] hits = Physics.OverlapSphere(transform.position, 5f);
    
        // 3. LINQ operations allocate iterators and delegates
        var activeEnemies = enemies.Where(e => e.IsAlive).ToList();
    }
    
    // GOOD: Zero heap allocation per frame
    private static readonly NonAllocArray<Collider> hitsBuffer = new(32);
    private readonly StringBuilder scoreBuilder = new(32);
    
    void GoodUpdate() {
        // 1. Reusable StringBuilder or StringFormatter
        scoreBuilder.Clear().Append("Score: ").Append(score);
        scoreText.SetText(scoreBuilder);
    
        // 2. NonAlloc physics queries reusing pre-allocated buffer
        int hitCount = Physics.OverlapSphereNonAlloc(transform.position, 5f, hitsBuffer.Array);
    
        // 3. Simple for-loops over arrays or lists
        for (int i = 0; i < enemies.Count; i++) {
            if (enemies[i].IsAlive) ProcessEnemy(enemies[i]);
        }
    }

    Code annotations

    1. Line 4

      String GC Alloc

      Strings are immutable reference types in C#. 'Score: ' + score allocates memory on the managed heap every tick.

      Effect: Triggers frequent Garbage Collection pauses every few seconds on mobile.

    2. Line 23

      NonAlloc Physics Buffer

      Physics.OverlapSphereNonAlloc populates an existing pre-allocated array without allocating a single byte.

      Effect: CPU cost is predictable and managed memory footprint stays perfectly flat.

  3. Mobile Optimization Checkpoint

    A mobile game runs at 60 FPS for the first 2 minutes, but then drops to 38 FPS and the phone gets warm. The Profiler shows no sudden CPU spike. What is happening?

    Expected reasoning

    Thermal Throttling. The game was using 100% of GPU/CPU capacity without headroom (>15ms active frame time). The phone's OS throttled the clock speed to prevent overheating. Target 10-12ms active time to keep devices cool.

Mobile 60 FPS Calculator

Unity Mobile Frame & Draw Call Budget

Simulate CPU draw call batches, dynamic lighting, and garbage collection stutter before testing on physical Android or iOS hardware.

Visible Mesh Renderers120 objects
Realtime Pixel Lights1 Light

60 FPS (Rock-Solid)

Your active frame time is under 12ms. Zero risk of thermal throttling.

Total Draw Calls30 / 100
Active Frame Time8 ms / 16.6ms
Key Mobile Performance Rules
  • Keep Draw Calls < 100: Combine mesh materials and enable GPU Instancing.
  • 0 B GC Alloc in Update: Use NonAlloc physics queries and StringBuilders.
  • Isolate Dirty Canvases: Never put moving health bars on the main UI root canvas.