界面已本地化;技能介绍与说明文档按所选语言由 AI 自动翻译,代码、命令、路径和专业术语保留原文,以原作者文档为准。
探索技能
开发与工程 · SKILL.md

unity-performance

unity-performance

【开发与工程】Unity performance — Profiler, Frame Debugger, Memory Profiler, GC allocation hunting, object pooling, IL2CPP build settings, Burst, batching, LOD, GPU Resident Drawer. USE WHEN: frame drops, GC spikes, long load times, memory growth, draw-call storms, mobile thermal/battery issues, profiling captures. DO NOT USE FOR: gameplay logic refactoring (use…

独立 GitHub 快照 · 自动分类 · 以原作者文档为准

技能说明

GitHub

name: unity-performance description: | Unity performance — Profiler, Frame Debugger, Memory Profiler, GC allocation hunting, object pooling, IL2CPP build settings, Burst, batching, LOD, GPU Resident Drawer.

USE WHEN: frame drops, GC spikes, long load times, memory growth, draw-call storms, mobile thermal/battery issues, profiling captures.

DO NOT USE FOR: gameplay logic refactoring (use unity-core); pipeline selection (use unity-rendering). allowed-tools: Read, Grep, Glob, Write, Edit

Unity Performance

Tools

  • Profiler (Window > Analysis > Profiler): CPU / GPU / Memory / Rendering / Audio / Physics.
  • Frame Debugger (Window > Analysis > Frame Debugger): step through draw calls, see batching breaks.
  • Memory Profiler package: snapshots, diff, find leaks.
  • Profile Analyzer package: aggregate frames across captures.
  • Use Deep Profile sparingly — adds overhead but shows method-level hotspots.

Build for profiling

Make a Development Build with Autoconnect Profiler + Deep Profiling Support. Don't profile editor — numbers are misleading.

GC allocation hunting

Common culprits:

CauseFix
string concatenation in UpdateStringBuilder reused, or only build when value changes
List<T>.ToArray() per frameCache list, reuse
foreach over some collections (boxing)for loop over IList<T>
GetComponent in UpdateCache in Awake
LINQ (.Where, .Select) per frameManual loops
Lambda capturing localsConvert to method or pre-allocate delegate

Read GC Alloc column in Profiler hierarchy — anything > 0 in Update is suspect.

Object pooling

private readonly IObjectPool<Bullet> _pool = new ObjectPool<Bullet>(
    createFunc:    () => Object.Instantiate(prefab),
    actionOnGet:   b => b.gameObject.SetActive(true),
    actionOnRelease: b => b.gameObject.SetActive(false),
    actionOnDestroy: Object.Destroy,
    defaultCapacity: 32, maxSize: 256);

public void Fire() {
    var b = _pool.Get();
    b.transform.position = muzzle.position;
    b.OnExpired = () => _pool.Release(b);
}

UnityEngine.Pool.ObjectPool<T> since Unity 2021.1. For SO-driven pools or ECS, use NativeArray-backed structures.

Burst + Jobs

[BurstCompile]
public struct ApplyGravityJob : IJobParallelFor {
    public NativeArray<float3> Velocities;
    public float DeltaTime;
    public void Execute(int i) {
        Velocities[i] += new float3(0, -9.81f * DeltaTime, 0);
    }
}

void Update() {
    var job = new ApplyGravityJob { Velocities = _velocities, DeltaTime = Time.deltaTime };
    var handle = job.Schedule(_velocities.Length, 64);
    handle.Complete();
}

Burst compiles to highly optimized native; works only on struct jobs with NativeArray/blittable types.

IL2CPP build settings

  • IL2CPP Code Generation: "Faster runtime" for shipping; "Faster (smaller) builds" for iteration.
  • Managed Stripping Level: Low/Medium for safety; High only with thorough QA + link.xml for reflection-only types.
  • Engine Code Stripping: enable to drop unused subsystems.

Batching & instancing

TechniqueWhen
Static BatchingMark static + same material → bake at build
Dynamic BatchingAuto for very small meshes; off in URP by default
GPU InstancingSame mesh + same shader, slight per-instance variation via MaterialPropertyBlock
SRP BatcherURP/HDRP default — same shader variant batched into one SetPass
GPU Resident Drawer (Unity 6)Auto-instancing for static objects with shared mesh+mat

LOD

LOD 0 = full mesh (close)
LOD 1 = half tris (medium)
LOD 2 = quarter tris (far)
LOD 3 = imposter or culled

Use LODGroup with screen-relative transition heights. Combine with Occlusion Culling for indoors.

Anti-patterns

Anti-patternFix
Profiling editor numbersProfile Development Build only
Camera.main per frameCache once
new Vector3(...) in Update with constantsMake static readonly
transform.GetChild(i).gameObject repeatedlyCache child references
Per-frame string.Format for HUD textUpdate only on value change
Profiler with deep profile shipped to QAOnly enable for short investigations

Production checklist

  • Frame budget hit on target devices (e.g. 16ms PC, 33ms mobile)
  • GC alloc per frame ≤ ~0 in steady state
  • Object pools for bullets/VFX/UI fly-outs
  • Burst-compiled jobs for hot math
  • LODGroup + Occlusion Culling tuned
  • Shader variants pre-warmed
  • Memory snapshot baseline + post-soak captured & diffed
我的收藏