字符串

有人可能会说,Unity 中的资源占用量比简陋的字符串要多,但它是早期修复的一个比较容易的方面。

字符串操作构建垃圾

大多数字符串操作都会构建很少量的垃圾,但如果在单次更新过程中多次调用这些操作,它就会堆积起来。随着时间的推移,它将触发自动垃圾收集,这可能导致可见的 CPU 峰值。

缓存字符串操作

请考虑以下示例。

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

void Update()
{
    for (var i = 0; i < 3; i++)
    {
        // Cached, no garbage generated
        Debug.Log(StringKeys[i]);
    }

    for (var i = 0; i < 3; i++)
    {
        // Not cached, garbage every cycle
        Debug.Log("Key" + i);
    }

    // The most memory-efficient way is to not create a cache at all and use literals or constants.
    // However, it is not necessarily the most readable or beautiful way.
    Debug.Log("Key0");
    Debug.Log("Key1");
    Debug.Log("Key2");
}

它可能看起来很愚蠢和多余,但如果你正在使用 Shaders,你可能会遇到这些情况。缓存密钥将有所作为。

请注意,字符串文字常量不会生成任何垃圾,因为它们会静态注入程序堆栈空间。如果你在运行时生成字符串并且保证每次都像上面的示例一样生成相同的字符串,则缓存肯定会有所帮助。

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

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

对 Debug 消息执行字符串操作,即。Debug.Log("Object Name: " + obj.name) 很好,在开发过程中无法避免。但是,确保不相关的调试消息不会在已发布的产品中结束是很重要的。

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

using UnityEngine;
using System.Collections;

public class ConditionalDebugExample: MonoBehaviour
{
    IEnumerator Start()
    {
        while(true)
        {
            // This message will pop up in Editor but not in builds
            Log("Elapsed: " + Time.timeSinceLevelLoad);
            yield return new WaitForSeconds(1f);
        }
    }

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

这是一个简化的例子。你可能希望花一些时间设计更完善的日志记录例程。

字符串比较

这是一个小的优化,但值得一提。比较字符串比人们想象的要多一些。系统将默认将文化差异考虑在内。你可以选择使用简单的二进制比较,其执行速度更快。

// Faster string comparison
if (strA.Equals(strB, System.StringComparison.Ordinal)) {...}
// Compared to
if (strA == strB) {...}

// Less overhead
if (!string.IsNullOrEmpty(strA)) {...}
// Compared to
if (strA == "") {...}

// Faster lookups
Dictionary<string, int> myDic = new Dictionary<string, int>(System.StringComparer.Ordinal);
// Compared to
Dictionary<string, int> myDictionary = new Dictionary<string, int>();