Skip to content

内存与性能相关

unity-csharp-memory-performance

核心理解

在 Unity 里,C# 性能最重要的一句话是:每帧少产生临时对象,先用 Profiler 找证据,再优化热点。

classstring、数组、很多集合对象会进入托管堆 Managed Heap。当这些对象不再被引用时,GC 会回收它们。但 GC 清理时可能打断游戏帧,所以你会看到卡顿、掉帧、手感不稳。

不要死背“值类型一定在栈上,引用类型一定在堆上”。对 Unity 新手更实用的判断是:

c
new List<int>();     // 分配对象
new int[100];        // 分配数组
"Score: " + score;   // 可能产生新字符串
object x = 10;       // int 被装箱,产生堆对象

最容易出问题的地方

UpdateFixedUpdate、大循环、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 常用优化习惯

缓存组件引用:AwakeStartGetComponent,不要每帧查。 复用集合:字段里建 List<T>,用 Clear() 清空,不要循环里反复 new。 提前给容量:new List<HitInfo>(128),减少自动扩容和复制。 减少字符串临时对象:UI 文本只在数值变化时刷新,大量拼接用 StringBuilder。 避免热点里的装箱:不要用 List<object>intfloat,用 List<int>List<float>。 避免热点里的闭包和 LINQ:它们写起来舒服,但可能产生隐藏分配。 对象池:子弹、特效、伤害数字、怪物复用,少用频繁 Instantiate/Destroy。 NonAlloc API:例如 Physics.RaycastNonAlloc,把结果数组传进去复用。

排查顺序

先打开 Window > Analysis > Profiler,看 CPU 里的 GC.Alloc。 如果看到某一帧分配很多,再开 allocation call stacks 找到是哪行代码。 内存整体变大、场景切换后不降,用 Memory Profiler 抓 snapshot 对比。 最后一定在目标设备上测,不要只看 Editor。

参考链接

文章评价

读完这篇,留下你的看法

暂无审核通过的评价。

登录账号后才能评价。

本站访客数0总站访问量0本页访问量0