PERFORMANCE_OPTIMIZATION_GUIDE

Performance Optimization Guide

Unity Tower Defense - Complete Reference

Version: 2.0 Last Updated: December 2025 Target Platform: Unity 2022.3 LTS + URP Optimization Results: +125% FPS (63.9 โ†’ 144.1)


๐Ÿ“š Table of Contents


1. Introduction

1.1 Document Purpose

This guide documents the complete performance optimization process for a Unity tower defense game, achieving +125% FPS improvement (63.9 โ†’ 144.1 FPS) through systematic CPU and GPU optimization.

Target Audience:

  • Unity developers optimizing performance

  • Technical leads reviewing optimization strategies

  • Game engineers learning profiling techniques

1.2 Project Context

Initial State:

  • FPS: 63.9 (Wave 7, 15 enemies)

  • CPU Time: 15.6ms per frame

  • Batches: 7,277

  • Shadow Casters: 9,125

  • Update() Calls: 11,900/second

Final State:

  • FPS: 144.1 (+125%)

  • CPU Time: 6.9ms (-56%)

  • Batches: 1,917 (-74%)

  • Shadow Casters: 83 (-99%)

  • Update() Calls: 50/second (-99.5%)

1.3 Optimization Philosophy

Core Principles

1. Measure Before Optimizing

Never optimize based on assumptions!

2. Target Bottlenecks First

3. Incremental Optimization

4. Know When to Stop


2. Profiling Methodology

2.1 Unity Profiler

Accessing the Profiler

Key Modules

CPU Usage Module:

Rendering Module:

Memory Module:

Profiling Workflow

CPU Profiler Example

Before Optimization:

After Optimization:

Key Insight: Batch processing reduced Update() overhead by 98%!

Performance Markers

Add custom markers for profiling specific sections:

Result: Custom marker appears in Profiler hierarchy for precise measurement.

2.2 Frame Debugger

Accessing Frame Debugger

What It Shows

Usage Workflow

Frame Debugger Example

Before Optimization:

After Optimization (SRP Batcher):

Key Insight: SRP Batcher combined 400 grid nodes into 6 batches!

Identifying SRP Batcher Compatibility

2.3 Stats Window

Enabling Stats

Key Metrics

Interpretation:

FPS (Frames Per Second):

Batches:

Saved by Batching:

SetPass Calls:

Shadow Casters:

Stats Window Caveats

โš ๏ธ Warning: Stats window has limitations!

Problem 1: SRP Batcher Not Reported

Problem 2: Batches Count Inconsistent

2.4 Profiling Best Practices

1. Profile in Build, Not Editor

Why?

How to Profile Build:

2. Test on Target Hardware

3. Profile Worst-Case Scenarios

4. Compare Apples to Apples

5. Record Multiple Samples


3. CPU Optimization Techniques

3.1 Batch Processing (Eliminating Update())

The Problem

Traditional Unity Pattern:

Overhead:

The Solution: System-Based Batch Processing

New Pattern:

Benefits:

Performance Impact

Test Setup:

  • 100 enemies moving

  • 60 FPS target

  • Unity 2022.3 LTS

Results:

Approach
Frame Time
Overhead
Speedup

Individual Update()

1.2ms

High

1ร— (baseline)

Batch Processing

0.06ms

Low

20ร—

Implementation Steps

Step 1: Define Interface

Step 2: Create System

Step 3: Refactor Entities

Step 4: Orchestrate Systems

3.2 Eliminating LINQ in Hot Paths

The Problem

LINQ is Slow:

Hidden Costs:

Performance Test:

The Solution: Manual Iteration

Targeting Strategy (Without LINQ):

Closest Target (Without LINQ):

Key Optimization: SqrMagnitude

Performance Impact

Test: 10 towers selecting targets (50 enemies each)

Approach
Time/Frame
Allocations
GC Impact

LINQ (OrderBy + First)

2.5ms

2.8 KB

High

Manual Iteration

0.1ms

0 bytes

None

Improvement

-96%

-100%

โœ…

Annual Impact (60 FPS):

When LINQ Is Acceptable

Outside Hot Paths:

Rule of Thumb:

3.3 Coroutines for Infrequent Tasks

The Problem

Expensive Operations in FixedUpdate:

Issues:

The Solution: Coroutine with Delay

Optimized Target Scanning:

Benefits:

Why It Works:

Performance Impact

Test: 10 towers scanning 50 enemies

Scan Rate
Physics Queries
CPU Time
FPS Impact

50/sec (FixedUpdate)

500/sec

3.0ms

Baseline

10/sec (0.1s coroutine)

100/sec

0.6ms

+8 FPS

5/sec (0.2s coroutine)

50/sec

0.3ms

+12 FPS

2/sec (0.5s coroutine)

20/sec

0.12ms

+15 FPS

Sweet Spot: 5 scans/second (0.2s delay)

  • Responsive enough for gameplay

  • 90% reduction in queries

  • No noticeable delay

When to Use Coroutines

Good Candidates:

Bad Candidates:

Guidelines:

3.4 Object Pooling

The Problem

Instantiate/Destroy Overhead:

Impact:

The Solution: Object Pool

Pool Manager Implementation:

Usage:

Critical: OnEnable vs Start

โš ๏ธ Pooled Objects Gotcha:

Why?

Performance Impact

Test: 100 projectiles spawning/despawning per second

Approach
Spawn Time
Destroy Time
GC/min
Total Overhead

Instantiate/Destroy

0.5ms

0.5ms

20 ร— 100ms

2,000ms/min

Object Pooling

0.01ms

0.01ms

0

120ms/min

Improvement

-98%

-98%

-100%

-94%

Pre-Warming Pools

Initialize pools at game start:

Benefits:

3.5 Component Caching

The Problem

GetComponent in Hot Paths:

The Solution: Cache in Awake

Performance Impact:

Best Practices

Cache All Frequently Used Components:

Even transform Benefits from Caching:


4. GPU Optimization Techniques

4.1 Shadow Optimization

The Problem

Excessive Shadow Casters:

The Solution: Disable Unnecessary Shadows

Runtime Shadow Disabling:

Performance Impact:

Which Objects Should Cast Shadows?

Guidelines:

Visual Test:

4.2 Static Batching

The Problem

Individual Draw Calls for Static Objects:

The Solution: Static Batching

Method 1: Mark Static in Inspector (Editor-Only)

Method 2: StaticBatchingUtility (Runtime)

Performance Impact:

Caveats:

4.3 SRP Batcher (URP)

What is SRP Batcher?

SRP Batcher = Scriptable Render Pipeline Batcher (Unity 2018.3+)

Purpose:

How It Works:

Enabling SRP Batcher

Global Setting:

Or in Inspector:

Material Compatibility

Requirements for SRP Batcher:

Checking Compatibility:

Performance Impact

Test: 400 Grid Nodes

Frame Debugger Evidence:

Stats Window Caveat

โš ๏ธ Stats Window Doesn't Show SRP Batcher Savings!

4.4 GPU Instancing

What is GPU Instancing?

GPU Instancing = Rendering many copies of same mesh/material in single draw call.

Use Case:

Enabling GPU Instancing

On Material:

Via Script:

Requirements

GPU Instancing Works When:

GPU Instancing Breaks When:

Per-Instance Properties (Advanced)

Problem: Want unique colors but same material?

Solution: MaterialPropertyBlock with instancing

Shader Support Required:

Performance Impact

Test: 50 Identical Enemies

4.5 Dynamic Batching

What is Dynamic Batching?

Dynamic Batching = Unity automatically combines small meshes at runtime.

Requirements:

Limitations:

Enabling Dynamic Batching

When to Use

Good for:

Not good for:

Recommendation:

Performance Impact


5. Memory Optimization

5.1 Garbage Collection (GC)

Understanding GC

What is Garbage Collection?

GC in Unity:

Identifying GC Issues

Unity Profiler:

Memory Profiler:

Reducing GC Pressure

Rule 1: Avoid Allocations in Hot Paths

Rule 2: Avoid String Concatenation

Rule 3: Cache Arrays

Rule 4: Avoid Boxing

Rule 5: Use Object Pooling

GC Performance Impact

Test: 60 seconds of gameplay

5.2 Texture Memory

Texture Compression

Problem:

Solution:

How to Compress:

Recommended Formats:

Mipmaps

What are Mipmaps?

Benefits:

When to Use Mipmaps:

Texture Atlasing

Problem:

Solution: Texture Atlas

Unity Tools:


6. Common Performance Pitfalls

6.1 Update() Overuse

Problem:

Solution:

6.2 FindObjectOfType in Update

Problem:

Solution:

6.3 Camera.main in Hot Paths

Problem:

Solution:

6.4 SendMessage / BroadcastMessage

Problem:

Solution:

6.5 Empty Update Methods

Problem:

Solution:

6.6 Physics.OverlapSphere Every Frame

Problem:

Solution:


7. Troubleshooting Guide

7.1 Low FPS Despite Optimizations

Symptom: FPS still low after optimization.

Diagnosis:

Solutions:

7.2 Frame Spikes

Symptom: Intermittent frame drops (100 FPS โ†’ 30 FPS โ†’ 100 FPS).

Diagnosis:

Solutions:

7.3 SRP Batcher Not Working

Symptom: Frame Debugger shows "RenderLoop.Draw" instead of "DrawSRPBatcher".

Diagnosis:

Solutions:

7.4 High Batch Count

Symptom: Batches > 3,000 despite optimization.

Diagnosis:

Solutions:

7.5 Memory Leaks

Symptom: Memory usage grows over time, eventually crashes.

Diagnosis:

Common Causes:

Solutions:


8. Best Practices

8.1 Profiling Workflow

8.2 Optimization Priority

8.3 When to Stop Optimizing


9. Tools Reference

9.1 Unity Profiler

Keyboard Shortcut: Ctrl+7 (Cmd+7 on Mac)

Key Modules:

  • CPU Usage: Method execution times

  • Rendering: Draw calls, batches

  • Memory: Allocations, GC

  • Physics: Collision checks

  • Audio: Sound overhead

Tips:

  • Record in Build mode (not Editor)

  • Use "Deep Profiling" for detailed call stacks (slow!)

  • Compare multiple samples for accuracy

9.2 Frame Debugger

Keyboard Shortcut: Ctrl+F7 (Cmd+F7 on Mac)

Use Cases:

  • Verify SRP Batcher working

  • Identify rendering order issues

  • Count actual draw calls

  • Debug shader issues

Tips:

  • Step through draws to find anomalies

  • Check for redundant state changes

  • Verify batching groups

9.3 Stats Window

Location: Game View โ†’ Stats (top-right)

Key Metrics:

  • FPS: Target 60+ (gameplay), 100+ (competitive)

  • Batches: <2,000 (good), <1,000 (excellent)

  • SetPass: <50 (excellent), <100 (good)

  • Tris: Depends on hardware

Caveats:

  • Doesn't show SRP Batcher savings

  • Includes all rendering (shadows, post-processing)

  • Use Frame Debugger for accuracy

9.4 Memory Profiler Package

Installation:

Use Cases:

  • Find memory leaks

  • Analyze heap allocations

  • Compare snapshots over time

  • Identify large objects


10. Case Studies

10.1 Tower Defense Optimization

Project: Procedurally Generated TD (this project)

Initial State:

  • FPS: 63.9 (Wave 7)

  • CPU: 15.6ms

  • Batches: 7,277

  • Shadow Casters: 9,125

Optimizations Applied:

Final State:

  • FPS: 144.1 (+125%)

  • CPU: 6.9ms (-56%)

  • Batches: 1,917 (-74%)

  • Shadow Casters: 83 (-99%)

Lessons Learned:

10.2 Key Takeaways


๐Ÿ“ Document Revision History

Version
Date
Changes

1.0

December 2024

Initial release (.docx)

2.0

December 2025

Complete rewrite (Markdown), expanded examples, case study


This Performance Optimization Guide is a living document. Contributions and feedback welcome.

Maintainer: Senior Unity Developer Last Review: December 2025 Next Review: June 2026

Last updated