Appearance
内存与性能相关
核心理解
在 Unity 里,C# 性能最重要的一句话是:每帧少产生临时对象,先用 Profiler 找证据,再优化热点。
class、string、数组、很多集合对象会进入托管堆 Managed Heap。当这些对象不再被引用时,GC 会回收它们。但 GC 清理时可能打断游戏帧,所以你会看到卡顿、掉帧、手感不稳。
不要死背“值类型一定在栈上,引用类型一定在堆上”。对 Unity 新手更实用的判断是:
c
new List<int>(); // 分配对象
new int[100]; // 分配数组
"Score: " + score; // 可能产生新字符串
object x = 10; // int 被装箱,产生堆对象最容易出问题的地方
Update、FixedUpdate、大循环、UI 刷新、物理查询、频繁生成销毁对象,都是高风险区域。因为它们执行次数太高,小问题会被放大。
坏写法:
c
void Update()
{
List<Enemy> enemies = new List<Enemy>();
scoreText.text = "Score: " + score;
}更好的写法:
c
private readonly List<Enemy> enemies = new(64);
private int oldScore = -1;
void Update()
{
enemies.Clear();
if (score != oldScore)
{
scoreText.text = score.ToString();
oldScore = score;
}
}Unity 常用优化习惯
缓存组件引用:Awake 或 Start 里 GetComponent,不要每帧查。 复用集合:字段里建 List<T>,用 Clear() 清空,不要循环里反复 new。 提前给容量:new List<HitInfo>(128),减少自动扩容和复制。 减少字符串临时对象:UI 文本只在数值变化时刷新,大量拼接用 StringBuilder。 避免热点里的装箱:不要用 List<object> 装 int、float,用 List<int>、List<float>。 避免热点里的闭包和 LINQ:它们写起来舒服,但可能产生隐藏分配。 对象池:子弹、特效、伤害数字、怪物复用,少用频繁 Instantiate/Destroy。 NonAlloc API:例如 Physics.RaycastNonAlloc,把结果数组传进去复用。
排查顺序
先打开 Window > Analysis > Profiler,看 CPU 里的 GC.Alloc。 如果看到某一帧分配很多,再开 allocation call stacks 找到是哪行代码。 内存整体变大、场景切换后不降,用 Memory Profiler 抓 snapshot 对比。 最后一定在目标设备上测,不要只看 Editor。
参考链接