unity3d 弦乐

示例

有人可能会争辩说,Unity中的资源消耗比谦卑的字符串还多,但这是早期更容易解决的方面之一。

字符串操作生成垃圾

大多数字符串操作会生成少量垃圾,但是如果在单个更新过程中多次调用了这些操作,则会堆积它们。随着时间的流逝,它将触发自动垃圾收集,这可能会导致可见的CPU峰值。

缓存您的字符串操作

考虑以下示例。

string[] StringKeys = new string[] {
    "Key0",
    "Key1",
    "Key2"
};

void Update()
{
    for (var i = 0; i < 3; i++)
    {
        // 缓存,不产生垃圾
        Debug.Log(StringKeys[i]);
    }

    for (var i = 0; i < 3; i++)
    {
        // 不缓存,每个周期都垃圾
        Debug.Log("Key" + i);
    }

    // 最节省内存的方法是根本不创建缓存,而使用文字或常量。
    // 但是,它不一定是最易读或美观的方法。
    Debug.Log("Key0");
    Debug.Log("Key1");
    Debug.Log("Key2");
}

它可能看起来很愚蠢且多余,但是如果您使用的是Shaders,则可能会遇到诸如此类的情况。缓存密钥将有所作为。

请注意,字符串文字常量不会产生任何垃圾,因为它们是静态注入程序堆栈空间的。如果您在运行时生成字符串,并且可以确保每次生成相同的字符串,如上面的示例,那么缓存肯定会有所帮助。

对于其他情况,每次生成的字符串都不相同,除了生成这些字符串,没有其他选择。这样,每次手动生成字符串的内存峰值通常可以忽略不计,除非一次生成数万个字符串。

大多数字符串操作都是调试消息

对调试消息进行字符串操作,即 Debug.Log("对象名称: " + obj.name)很好,在开发过程中无法避免。但是,重要的是要确保无关的调试消息不会最终发布在产品中。

一种方法是在调试调用中使用Conditional属性。这不仅删除了方法调用,还删除了其中所有的字符串操作。

using UnityEngine;
using System.Collections;

public class ConditionalDebugExample: MonoBehaviour
{
    IEnumerator Start()
    {
        while(true)
        {
            // 该消息将在“编辑器”中弹出,但不会在内部版本中弹出
            Log("Elapsed: " + Time.timeSinceLevelLoad);
            yield return new WaitForSeconds(1f);
        }
    }

    [System.Diagnostics.Conditional("UNITY_EDITOR")]
    void Log(string Message)
    {
        Debug.Log(Message);
    }
}

这是一个简化的示例。您可能需要花费一些时间来设计更完善的日志记录例程。

字符串比较

这是次要的优化,但值得一提。比较字符串比人们想象的要复杂得多。系统默认会尝试考虑文化差异。您可以选择使用简单的二进制比较,它执行起来更快。

// 更快的字符串比较
if (strA.Equals(strB, System.StringComparison.Ordinal)) {...}
// 相比
if (strA == strB) {...}

// 减少开销
if (!string.IsNullOrEmpty(strA)) {...}
// 相比
if (strA == "") {...}

// 更快的查询
Dictionary<string, int> myDic = new Dictionary<string, int>(System.StringComparer.Ordinal);
// 相比
Dictionary<string, int> myDictionary = new Dictionary<string, int>();