美文网首页
Unity 关于代码(cpu)优化的建议摘录

Unity 关于代码(cpu)优化的建议摘录

作者: 宅7 | 来源:发表于2021-06-14 15:44 被阅读0次

    1.对于不能使用事件触发的代码段,并不意味着每一帧都要去处理。

    void Update()

    {

        ExampleExpensiveFunction();

    }

    可以通过以下代码将这些逻辑每隔x 帧做一次处理。

    void Update()

    {

        if(Time.frameCount % interval == 0)

            ExampleExpensiveFunction();

    }

    或者可以通过如下代码将重量级的逻辑拆分到不同的帧去执行

    void Update()

    {

        if(Time.frameCount % interval ==0)

            ExampleExpensiveFunction1();

        else if(Time.frameCount % interval == 1)

            ExampleExpensiveFunction2();

    }

    2.尽量少使用的昂贵API

    SendMessage() BroadcastMessage() 内部使用了反射,使用事件或代理替代。

    Find() 需要Unity 遍历所有内存中的GameObject,建议不要使用。

    Transform.rotation Transform.position 设置Transform 的旋转和世界坐标会触发OnTransformChange 通知其所有的子孙Transform,因此相对来说比较昂贵尤其是那些有很多子孙的Transform,应该尽量避免频繁地赋值。

    获取位置信息时,优先使用Transform.localPosition 而不是Transform.position,后者每次调用时都会重新计算物体的世界坐标,而localPosition 则是一个缓存在Transform 中的变量,如果需要频繁使用世界坐标,那么建议缓存下来。

    Update() LateUpdate() 等生命期函数都有隐藏的消耗,所以即使是函数内部什么也不做也有消耗,建议不要保留空的生命期函数,尤其是Update() 这种每帧都会调用的生命期函数。

    Vector Vector 系列的magiture 方法和Distance 方法使用了平方根计算,当仅仅需要比较两个向量的长度的时候,使用sqrMagnitude 效率更高。

    Camera.main 不要使用,原因是内部调用了Find() 方法。

    3.利用是否在视椎体内的信息来优化代码。

    private Renderer myRenderer;

    void Start()

    {

        myRenderer = GetComponent<Renderer>();

    }

    void Update()

    {

        UpdateTransformPosition();

        if(myRenderer.isVisible)

        {

            ExampleExpensiveFunction();

        }

    }

    4.可以使用LOD 技术提供的信息来优化代码

    Unity 提供了CullingGroup API 用来提供给开发者Culling 和LOD 相关的信息,使用这些信息可以实现类似meshrenderer 的基于距离来执行不同效果的逻辑。

    5.关于垃圾回收相关的优化建议

    减少代码产生垃圾的建议:

    缓存:经常重复调用的方法中如果有堆内存分配和回收逻辑,应该在特定时期将这些引用缓存下来,避免每次调用都要分配对内存

    void OnTriggerEnter(Collider other)

    {

        Renderer[] allRenderers = FindObjectsOfType<Renderer>();

        ExampleFunction(allRenderers);

    }

    改为

    private Renderer[] allRenderers;

    void Start()

    {

        allRenderers = FindObjectsOfType<Renderer>();

    }

    void OnTriggerEnter(Collider other)

    {

        ExampleFunction(allRenderers);

    }

    不要在频繁调用的方法(Update)中分配堆内存

    使用容器类时,使用Clear() 方法代替生成新容器(或者使用容器池)

    创建新的容器类实例时会触发堆内存分配,可能会触发垃圾回收

    List myList = new List();

    改为

    myList.Clear();

    使用对象池技术处理频繁创建和销毁的物体

    不要频繁操作(合并、截取等)string 类型的数据

    string 是引用且不可变类型,每次操作string 类型后,都会重新创建新的string 类型,可能会触发垃圾回收

    创建string 时如果需要进行合并操作,可以使用StringBuilder 类用于轻量级地创建string。

    移除所有不需要的Debug.Log 方法调用,每个Debug.Log 都至少会创建和销毁至少一个string。

    需要显示的string 数据,如果需要合并操作,将string 数据拆分成不变的部分和变化的部分,以移除+ 操作。

    public Text timerText;

    void Update()

    {

        timerText.text = "Time:" + DateTime.Now.ToString();

    }

    改为

    public Text headerText, timerText;

    void Start()

    {

        headerText.text = "Time";

    }

    void Update()

    {

        timerText = DataTime.Now.ToString();

    }

    警惕那些返回数组、容器等的Unity 内置API,因为每次调用他们都会返回一个新的引用,可能引发垃圾回收,如需频繁使用,建议获取一次后暂存下来。

    尽量减少装箱和拆箱操作

    创建协程会造成垃圾,因为Unity 需要为每个协程创建管理类实例。

    yield return 0;

    会造成装箱装换,改为

    yield return null;

    可以避免装箱引起的堆内存分配

    while(!isComplete)

    {

        yield return new WaitForSenconds(1f);

    }

    改为

    WaitForSeconds delay = new WaitForSeconds(1f);

    while(!isComplete)

    {

        yield return delay;

    }

    可以减少垃圾产生。

    匿名方法是引用类型会产生垃圾,尤其是闭包会显著增加内存使用和分配。

    LINQ 和正则表达式会产生垃圾,因为其内部操作会昌盛装箱操作。

    避免使用枚举作为字典的key,因为会产生装箱操作,必须使用时,实现IEqualityComparer 接口并将其实例作为字典的比较器。

    public class MyEnumComparer : IEqualityComparer<MyEnum>

    {

        public bool Equals(MyEnum x, MyEnum y)

        {

            return x==y;

        }

        public int GetHashCode(MyEnum x)

        {

            return (int)x;

        }

    }

    避免在结构体中添加引用类型字段(包括字符串类型),因为包含了引用类型的结构体需要被垃圾回收器完整检测,对那些不是引用类型的变量也做了不必要的检测。可以尝试将引用类型拆分出来。

    减少不必要的引用缓存,可以减少垃圾回收器检索引用所用的时间。

    在不会影响玩家体验的时间点(如场景加载显示Loading 界面时)调用System.GC.Collect() 来主动回收垃圾。

    相关文章

      网友评论

          本文标题:Unity 关于代码(cpu)优化的建议摘录

          本文链接:https://www.haomeiwen.com/subject/nmdneltx.html