unity-performance
Systematic approach to profiling and optimizing Unity games. Covers profiling tools, CPU/GPU optimization, memory management, rendering optimization, and platform-specific considerations.
Works with
Agent Skills format with YAML frontmatter. Claude Code reads it as-is.
---
name: "unity-performance"
description: "Systematic approach to profiling and optimizing Unity games. Covers profiling tools, CPU/GPU optimization, memory management, rendering optimization, and platform-specific considerations."
license: "MIT"
---
# Unity Performance Optimization
## Overview
Systematic approach to profiling and optimizing Unity games. Covers profiling tools, CPU/GPU optimization, memory management, rendering optimization, and platform-specific considerations.
## Profiling Tools
| Tool | What It Shows | When to Use |
|------|--------------|-------------|
| **Unity Profiler** | CPU, GPU, memory, audio, physics per frame | First stop for any perf issue |
| **Frame Debugger** | Draw call breakdown, shader/material state | Rendering bottlenecks |
| **Memory Profiler** | Heap snapshots, texture/mesh memory | Memory leaks, bloat |
| **Profile Analyzer** | Compare captures, statistical analysis | Before/after optimization |
| **Physics Debugger** | Collider visualization, contact points | Physics performance |
### Profiler Workflow
1. Build with Development Build + Autoconnect Profiler enabled
2. Profile on target device (not in Editor -- Editor overhead distorts results)
3. Identify the bottleneck category: CPU-bound, GPU-bound, or memory pressure
4. Drill into the specific system causing the issue
5. Optimize, re-profile, and compare
### Reading the Profiler
```text
If frame time > 16.6ms (60 FPS target):
CPU timeline > GPU timeline -> CPU-bound
GPU timeline > CPU timeline -> GPU-bound
GC.Alloc column shows per-frame allocations -> GC pressure
```
Look for spikes (single bad frames) vs. sustained high times (baseline too heavy).
## CPU Optimization
### Reduce Per-Frame Allocations (GC)
| Anti-Pattern | Fix |
|-------------|-----|
| `string + string` in Update | Use `StringBuilder` or cache |
| `new List<T>()` every frame | Allocate once, `Clear()` and reuse |
| LINQ in hot paths | Replace with manual loops |
| `GetComponent<T>()` per frame | Cache in Awake/Start |
| `GameObject.Find()` per frame | Cache reference or use events |
| `foreach` on non-generic collections | Use `for` loop or generic collections |
| `SendMessage()` / `BroadcastMessage()` | Use direct calls, events, or interfaces |
| Boxing value types | Use generic collections, avoid `object` casts |
### Object Pooling
```csharp
public class ObjectPool<T> where T : Component
{
readonly Queue<T> _pool = new();
readonly T _prefab;
readonly Transform _parent;
public ObjectPool(T prefab, int preWarm, Transform parent = null)
{
_prefab = prefab;
_parent = parent;
for (int i = 0; i < preWarm; i++)
_pool.Enqueue(CreateInstance());
}
public T Get(Vector3 position, Quaternion rotation)
{
var obj = _pool.Count > 0 ? _pool.Dequeue() : CreateInstance();
obj.transform.SetPositionAndRotation(position, rotation);
obj.gameObject.SetActive(true);
return obj;
}
public void Return(T obj)
{
obj.gameObject.SetActive(false);
_pool.Enqueue(obj);
}
T CreateInstance()
{
var obj = Object.Instantiate(_prefab, _parent);
obj.gameObject.SetActive(false);
return obj;
}
}
```
Pool bullets, particles, enemies, UI elements -- anything instantiated/destroyed frequently. Unity 2021+ also has `UnityEngine.Pool.ObjectPool<T>` built-in.
### Update Optimization
| Technique | Description |
|-----------|-------------|
| Stagger updates | Don't update all AI every frame; use tick groups |
| Distance-based LOD | Reduce update frequency for distant objects |
| Event-driven | Replace polling with events where possible |
| Disable unused scripts | `enabled = false` on off-screen components |
| Use `InvokeRepeating` | For periodic checks (cheaper than coroutine yielding) |
## GPU / Rendering Optimization
### Draw Call Reduction
| Technique | How | Savings |
|-----------|-----|---------|
| **Static Batching** | Mark non-moving objects as Static | Combines meshes at build time |
| **Dynamic Batching** | Automatic for small meshes (<300 verts) | URP/Built-in only |
| **GPU Instancing** | Enable on materials for repeated objects | Trees, grass, rocks |
| **SRP Batcher** | Enabled by default in URP/HDRP | Reduces SetPass calls |
| **Texture Atlasing** | Combine textures into atlas | Fewer material switches |
| **Mesh Combining** | `CombineMeshes()` at runtime | Custom batching |
### LOD (Level of Detail)
```text
LOD Group Setup:
LOD 0 (0-30%): Full-detail mesh (5000 tris)
LOD 1 (30-60%): Medium mesh (2000 tris)
LOD 2 (60-90%): Low mesh (500 tris)
Culled (90%+): Not rendered
```
Use LOD for meshes, but also reduce script complexity, particle counts, and physics at distance.
### Occlusion Culling
Bake occlusion data for indoor/complex scenes. Mark large static occluders (walls, floors). Configure cell size based on scene scale. Use the Occlusion Culling window to visualize and test.
### Shader Optimization
| Issue | Solution |
|-------|----------|
| Complex fragment shaders | Reduce texture samples, simplify math |
| Overdraw | Minimize transparent objects, use opaque when possible |
| Too many variants | Strip unused shader variants in build settings |
| Expensive post-processing | Disable effects on mobile, use cheaper alternatives |
## Memory Management
### Common Memory Issues
| Issue | Symptom | Fix |
|-------|---------|-----|
| Texture bloat | High memory, long loads | Compress textures, reduce max size per platform |
| Unloaded scenes holding refs | Memory climbs over time | Use `Resources.UnloadUnusedAssets()` after scene transitions |
| Addressables not released | Bundles stay in memory | Call `Addressables.Release(handle)` |
| Audio clips uncompressed | Huge memory footprint | Use compressed in memory for music, decompress on load for SFX |
| Mesh read/write enabled | Double memory per mesh | Disable Read/Write if not needed at runtime |
### Texture Compression Per Platform
| Platform | Format | Notes |
|----------|--------|-------|
| PC/Console | BC7 (DXT) | Best quality/size ratio |
| Android | ASTC 6x6 | Universal, scalable quality |
| iOS | ASTC 6x6 | Same as Android |
| WebGL | ETC2 / DXT | Depends on target GPU |
Use "Override for [Platform]" in texture import settings. Set max texture size to the minimum needed (512 for UI icons, 1024 for props, 2048 for hero assets).
## Platform-Specific Considerations
| Platform | Key Constraints |
|----------|----------------|
| **Mobile** | Thermal throttling, limited memory, battery drain, fill-rate limited |
| **WebGL** | No threads (pre-Unity 6), large download size, no compute shaders |
| **Console** | Certification requirements, fixed hardware, memory budgets |
| **VR/XR** | 72-90 FPS minimum, stereo rendering cost, motion sickness from drops |
## Addressables and Asset Loading
Use Addressables for async asset loading to avoid load-time hitches:
```csharp
// Preload during loading screen
var handle = Addressables.LoadAssetAsync<GameObject>("enemy_boss");
await handle;
// Release when done
Addressables.Release(handle);
```
Use Addressable groups to control bundle granularity. Mark infrequently used assets as remote/on-demand. Profile bundle memory with the Addressables Event Viewer.
## Quick Optimization Checklist
- [ ] Profile on target device, not in Editor
- [ ] Zero per-frame GC allocations in gameplay code
- [ ] Object pooling for all frequently spawned objects
- [ ] Static batching enabled for non-moving objects
- [ ] LOD groups on all 3D models visible at varying distances
- [ ] Textures compressed per platform with appropriate max sizes
- [ ] Disable Read/Write on meshes and textures not modified at runtime
- [ ] Audio clips use appropriate compression settings
- [ ] Occlusion culling baked for indoor/complex scenes
- [ ] Shader variants stripped in build settings
## Additional Resources
### Reference Files
- **`references/profiling-deep-dive.md`** -- Advanced Profiler usage, memory profiler snapshots, frame-by-frame analysis, custom profiler markers, automated performance testing, build size analysis, ECS/DOTS performance patternsMore General & Other skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.

