【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 执行时间也是之前的一半。

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