【Unity優化】Unity字符串String優化

【Unity優化】Unity字符串String優化

System.String

在這裏插入圖片描述

通過跟蹤Unity的string,我們看到了Unity給我們提供的各種string接口。發現該代碼來自mscorlib.dll,通過路徑直接找到該dll

Editor\Data\MonoBleedingEdge\lib\mono\unity\mscorlib.dll

我們通過dnSpy這個工具來對mscorlib.dll進行反編譯。打開dnSpy軟件通過“文件/打開”找到該dll,將其加載進來。

在這裏插入圖片描述

根據string的命名空間直接找到“System”的“String”類

在這裏插入圖片描述

string.Format

在這裏插入圖片描述

通過反編譯,我們看到string.Format在最終的實現過程中是重新new了一個StringBuilder。因此我們在對字符串進行Format操作的時候直接共用一個StringBuilder即可,具體實現如下

    private static StringBuilder stringBuilder = new StringBuilder();

    public static string Format(string src, params object[] args)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.AppendFormat(src, args);
        return stringBuilder.ToString();
    }

但是其實StringBuilder.Format的消耗也是挺大的,我們看看內部實現
在這裏插入圖片描述
在這裏插入圖片描述

最終調用的是AppendFormatHelper這個函數,裏面實現也是極其複雜,這裏也只是截取了一小部分,因此能不用Format的時候儘量不用Format,可以考慮使用Concat函數來代替。

string.Concat

在這裏插入圖片描述

string.Concat每次使用都會重新生成一個string,然後對其進行數據填充。當我們需要Concat的數據比較多的時候實際上是調用下面這個方法
在這裏插入圖片描述
在這裏插入圖片描述

裏面每次都會判斷填充的數據是否爲null,循環體裏都會有個object轉string的操作,其實大可不必如此。既然我們之前已經有一個通用的StringBuilder了,可以直接公用即可,每次使用之前清除掉舊數據,實現循環使用。

    public static string Concat(string s1,string s2)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(s1);
        stringBuilder.Append(s2);
        return stringBuilder.ToString();
    }

如果有多個參數s1,s2…就寫多個Concat函數,如果在外部調用的時候遇到循環體可以在這邊定義一個外部共享的StringBuilder,具體如下

    private static StringBuilder shareStringBuilder = new StringBuilder();

    public static StringBuilder GetShareStringBuilder()
    {
        shareStringBuilder.Remove(0, stringBuilder.Length);
        return shareStringBuilder;
    }

外部調用如下

    public void Test()
    {
        StringBuilder stringBuilder = QString.GetShareStringBuilder();
        for (int i = 0; i < 100; i++)
        {
            stringBuilder.Append(i);
        }
        Debug.Log(stringBuilder.ToString());
    }

完整代碼如下

using System.Text;
using UnityEngine;

/// <summary>
/// 字符串優化類
/// </summary>
public class QString
{
    private static StringBuilder stringBuilder = new StringBuilder();
    private static StringBuilder shareStringBuilder = new StringBuilder();

    public static StringBuilder GetShareStringBuilder()
    {
        shareStringBuilder.Remove(0, stringBuilder.Length);
        return shareStringBuilder;
    }

    public static string Format(string src, params object[] args)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.AppendFormat(src, args);
        return stringBuilder.ToString();
    }

    public static string Concat(string s1, string s2)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(s1);
        stringBuilder.Append(s2);
        return stringBuilder.ToString();
    }

    public static string Concat(string s1, string s2, string s3)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(s1);
        stringBuilder.Append(s2);
        stringBuilder.Append(s3);
        return stringBuilder.ToString();
    }
}

public class QStringSample
{
    public void Test()
    {
        StringBuilder stringBuilder = QString.GetShareStringBuilder();
        for (int i = 0; i < 100; i++)
        {
            stringBuilder.Append(i);
        }
        Debug.Log(stringBuilder.ToString());
    }
}

通過實驗進行數據對比

using UnityEngine;
using System.Text;
using UnityEngine.Profiling;

public class QStringTest : MonoBehaviour
{
    private void Update()
    {
        Before();

        After();
    }

    string s1 = string.Empty;
    private void Before()
    {
        Profiler.BeginSample("Before");
        s1 = string.Empty;
        for (int i = 0; i < 100; i++)
        {
            s1 += i;
        }
        Profiler.EndSample();
    }

    StringBuilder stringBuilder = QString.GetShareStringBuilder();
    private void After()
    {
        Profiler.BeginSample("After");
        stringBuilder.Remove(0, stringBuilder.Length);
        for (int i = 0; i < 100; i++)
        {
            stringBuilder.Append(i);
        }
        Profiler.EndSample();
    }
}

在這裏插入圖片描述

優化前的GC是25.2KB 優化後的GC只有2.9kB 執行時間也是之前的一半。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章