Version: 2020.3
Resources 文件夹
特别优化

一般优化

There are as many different ways to optimize code as there are reasons for performance problems. In general, it’s strongly recommended that developers closely profile their applications before attempting to apply CPU optimizations. However, there are several simple CPU optimizations that are universally applicable.

按 ID 寻址属性

Unity doesn’t use string names to address Animator, Material, and Shader properties internally. For speed, all property names are hashed into property IDs, and it’s these IDs that are actually used to address the properties.

Therefore, whenever using a Set or Get method on an Animator, Material or Shader, use the integer-valued method instead of the string-valued methods. The string methods perform string hashing and then forward the hashed ID to the integer-valued methods.

从字符串哈希创建的属性 ID 在单次运行过程中是不变的。它们最简单的用法是为每个属性名称声明一个静态只读整数变量,然后使用整数变量代替字符串。启动期间将自动进行初始化,无需其他初始化代码。

Animator.StringToHash 是用于 Animator 属性名称的对应 API,Shader.PropertyToID 是用于 Material 和 Shader 属性名称的对应 API。

使用非分配物理 API

In Unity 5.3 and onwards, non-allocating versions of all Physics query APIs have been introduced. Replace RaycastAll calls with RaycastNonAlloc, SphereCastAll calls with SphereCastNonAlloc. For 2D applications, there are also non-allocating versions of all Physics2D query APIs.

与 UnityEngine.Object 子类进行 Null 比较

The Mono and IL2CPP runtimes treat instances of classes that derive from UnityEngine.Object in a specific way. Invoking methods on the instances actually calls into engine code, which must perform lookups and validations to convert the script references to the native references. It’s more resource intensive to compare a variable of this type to null than to compare against a purely C# class. For this reason, avoid these null comparisons in tight loops or in code that runs every frame.

矢量和四元数数学以及运算顺序

For vector and quaternion math that’s located in tight loops, remember that integer math is faster than floating-point math, and floating-point math is faster than vector, matrix or quaternion math.

Therefore, whenever commutative or associative arithmetic allows, attempt to minimize the resource intensity of individual mathematical operations:


Vector3 x;

int a, b;

// 效率较低:产生两次矢量乘法

Vector3 slow = a * x * b;

// 效率较高:一次整数乘法、一次矢量乘法

Vector3 fast = a * b * x;

内置 ColorUtility

It’s common for applications that must convert between HTML-formatted color strings (#RRGGBBAA) and Unity’s native Color and Color32 structures to use a script from the Unify Community. This script was both slow and caused extensive memory allocation due to string manipulation.

从 Unity 5 开始,有一个内置 ColorUtility API 可以有效执行此类转换。应优先使用内置 API。

Find 和 FindObjectOfType

It’s a general best practice to eliminate all usage of GameObject.Find and Object.FindObjectOfType in production code. As these APIs require Unity to iterate over all GameObjects and Components in memory, they rapidly become non-performant as the scope of a project grows.

在单例对象的访问器对上述规则来说是个例外。全局管理器对象往往会暴露“instance”属性,并且通常在 getter 中存在 FindObjectOfType 调用以便检测单例预先存在的实例:


class SomeSingleton {

    private SomeSingleton _instance;

    public SomeSingleton Instance {

        get {

            if(_instance == null) { 

                _instance =

                    FindObjectOfType<SomeSingleton>(); 

            }

            if(_instance == null) { 

                _instance = CreateSomeSingleton();

            }

            return _instance;

        }

    }

}

While this pattern is generally acceptable, it’s important to examine the code and ensure that the accessor is be called in Scenes where the singleton object doesn’t exist. If the getter doesn’t automatically create an instance of a missing singleton, it’s common to discover that code looking for the singleton results in repeated calls to FindObjectOfType (often multiple times per frame) and creates an undesirable drain on performance.

调试代码和 [conditional] 属性

The UnityEngine.Debug logging APIs aren’t stripped from non-development builds, and do write to log files if called. As most developers don’t intend to write debug information in non-development builds, it’s recommended to wrap development-only logging calls in custom methods, like so:


    public static class Logger {

            [Conditional("ENABLE_LOGS")]

            public static void Debug(string logMsg) {

                UnityEngine.Debug.Log(logMsg);

            }

        }

通过使用 [Conditional] 属性来修饰这些方法,Conditional 属性所使用的一个或多个定义将决定被修饰的方法是否包含在已编译的源代码中。

如果传递给 Conditional 属性的任何定义均未被定义,则会被修饰的方法以及对被修饰方法的所有调用都会在编译中剔除。实际效果与包裹在 #if … #endif 预处理器代码块中的方法以及对该方法的所有调用的处理情况相同。

有关 Conditional 属性的更多信息,请参阅 MSDN 网站:msdn.microsoft.com

Resources 文件夹
特别优化
Copyright © 2023 Unity Technologies
优美缔软件(上海)有限公司 版权所有
"Unity"、Unity 徽标及其他 Unity 商标是 Unity Technologies 或其附属机构在美国及其他地区的商标或注册商标。其他名称或品牌是其各自所有者的商标。
公安部备案号:
31010902002961