處理字符串和文本是Unity項目中性能問題的常見來源迂猴。在C#中,所有的字符串都是不可變的。對字符串的任何操作都將導(dǎo)致分配一個完整的新字符串躺屁。
當(dāng)連接N個字符串的時候,會有N-1中間字符串分配经宏,依次連接也會給內(nèi)存管理帶來壓力犀暑。對于需要進(jìn)行連接的字符串,推薦用StringBuild去減傷內(nèi)存分配烁兰。一個StringBuild的實例可以重復(fù)使用耐亏,進(jìn)一步減少內(nèi)存分配。
重復(fù)字符串
在查看Mono內(nèi)存的時候發(fā)現(xiàn)字符串是內(nèi)存的使用大頭沪斟,發(fā)現(xiàn)里面會存在很多重復(fù)的字符串广辰。這些字符串都是運行時創(chuàng)建的,因為沒有消除重復(fù)導(dǎo)致占用大量內(nèi)存主之。
當(dāng)讀取一個N行的文件择吊,每行的內(nèi)容都是一樣的時候,這個字符串會再內(nèi)存中創(chuàng)建N份槽奕。推薦用String.Intern & String.IsInterned來管理字符串几睛。對所有創(chuàng)建出來的常駐String做一次String.Intern操作,則可以使所有字符串唯一粤攒。對非常駐的String所森,我們可以自己創(chuàng)建一個StringPool來維護(hù)唯一字符串,在合適的時機釋放這個Pool清理內(nèi)存夯接。
字符串比較
在字符串相關(guān)代碼中經(jīng)常發(fā)現(xiàn)的核心性能問題之一是使用默認(rèn)的慢速API焕济。這些API接口的默認(rèn)行為是能處理不同文化與語言規(guī)則的字符串。
string separated = "\u0061\u030a";
string combined = "\u00e5";
Console.WriteLine(String.Compare(separated, combined) == 0);
// result is True
Console.WriteLine(String.Compare(separated, combined, StringComparison.Ordinal) == 0);
// result is False
復(fù)雜的規(guī)則必然帶來的是執(zhí)行的不高效盔几,而且這功能在大部分的Unity工程里面是不需要的晴弃。
低效的字符串API
寫了一個簡單的腳步測試字符串API的速度
StringBuilder sBuilder = new StringBuilder();
System.Random random = new System.Random();
for (int i = 0; i < 100; ++i)
{
sBuilder.Append((char)(random.Next() % 256));
}
string str = sBuilder.ToString();
string preStr = str.Substring(0, 16);
string lastStr = str.Substring(str.Length - 16, 16);
int cnt = 0;
for (int i = 0; i < 100 * 1024; ++i)
{
if (str.StartsWith(preStr)) ++cnt;
if (str.StartsWith(lastStr)) ++cnt;
}
測試結(jié)果
Method | Time(ms) 100k compares |
---|---|
String.StartsWith,default culture | 360ms |
String.EndsWith,default culture | 12465ms |
String.StartsWith,Ordinal | 357ms |
String.EndsWith,Ordinal | 174ms |
CustomStartsWith | 18ms |
CustomEndsWith | 17ms |
字符串比較接口默認(rèn)行為
Func Name | Default interpretation |
---|---|
String.Compare | StringComparison.CurrentCulture |
String.CompareTo | StringComparison.CurrentCulture |
String.Equals | StringComparison.Ordinal |
String.ToUpper | StringComparison.CurrentCulture |
Char.ToUpper | StringComparison.CurrentCulture |
String.StartsWith | StringComparison.CurrentCulture |
String.IndexOf | StringComparison.CurrentCulture |