首页 > Unity3D频道 > 【Unity3D研究院之游戏开发】 > Unity3D研究院之字符串拼接0GC(一百零四)
2019
06-10

Unity3D研究院之字符串拼接0GC(一百零四)

最近在优化项目,发现字符串拼接的堆内存非常大,而且非常频繁。
大概原因如下
1.字符串就是char[] 长短发生变化必然要重新分配长度,以及拷贝之前的部分,产生GC
2.字符串+=进行拼接会产生装箱,生成GC
3.Append传入值类型数据,它会调用ToString方法,需要new string 然后把char[]拷进去,又会产生堆内存。
4.new StringBuidler 产生堆内存
5.StringBuidler.ToString 产生堆内存
5.string.format 它内部使用的就是StringBuilder,但是 1)new StringBuilder 2)Append 3)ToString都会产生堆内存。

所以我们需要优化的是
1.
int a = 100;
string b = a + “”;

禁止上述这种写法,会额外产生一次装箱操作。所以要采用如下写法。
string b = a.ToString();

2.少用或者不用string.format,提前缓存共享StringBuilder对象。避免用时候产生堆内存。
3.网上找到一个算法,挺有意思。提前定义好 0 – 9 之间的字符数组,如果传入值类型数据,从高位依次除以10算出每一位的数,然后再去预先声明的0-9字符数组中找对应的char,这样就就不会产生装箱GC了。
4.如果可以提前确定字符串的长度,例如,界面上显示玩家的等级, 我们可以确定level不可能超过3位数也就是100,那么可以提前声明一个长度为3的StringBuilder,通过反射取出来内部的_str,这样就可以避免最后的ToString产生的堆内存了。由于_str内容可能无法擦掉之前的所以需要调用GarbageFreeClear();方法。

1.装箱版本

Unity3D研究院之字符串拼接0GC(一百零四) - 雨松MOMO程序研究院 - 1

2.无装箱版本

Unity3D研究院之字符串拼接0GC(一百零四) - 雨松MOMO程序研究院 - 2

通通过这两张图大家可以看出来装箱和不装箱对GC有多大的影响了,还有最后的无GC版本。代码参考了下面的这两篇文章。

http://www.gavpugh.com/2010/04/05/xnac-a-garbage-free-stringbuilder-format-method/
http://www.gavpugh.com/2010/03/23/xnac-stringbuilder-to-string-with-no-garbage/

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院之字符串拼接0GC(一百零四)》有 5 条评论

  1. JingFengJi 说:

    StrExt.Format 貌似没有处理带”#”号的format

  2. MiKiNuo 说:

    发现如下问题:
    1、把上面的脚本在空unity下跑会报错空引用,
    private void Start()
    {
    m_StringBuildertxt = m_StringBuilder.GetGarbageFreeString();
    }
    public static string GetGarbageFreeString(this StringBuilder string_builder)
    {
    return (string)string_builder.GetType().GetField(“_str”, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(string_builder);
    }
    方法GetField()肯能空
    2、Profiler.BeginSample(“EmptyGC”);
    m_StringBuilder.GarbageFreeClear();
    m_StringBuilder.ConcatFormat(“{0}{1:0.00}{2:0.00}{3}”, i, f, d, s);
    string s5 = m_StringBuildertxt;
    Profiler.EndSample();
    这里s5一直为空字符串,如果m_StringBuilder.ToString()还是有GC

  3. foxxof 说:

    博主你好,unity版本是2018.4,运行无装箱例子的时候报错,反射的时候获取stringbuilder的_str为null。
    NullReferenceException: Object reference not set to an instance of an object
    StringBuilderExtensions.GetGarbageFreeString (System.Text.StringBuilder string_builder) (at Assets/LuaFramework/Scripts/Utility/StringBuilderExtensions.cs:368)
    NewBehaviourScript.Start () (at Assets/LuaFramework/Scripts/NewBehaviourScript.cs:12)

留下一个回复

你的email不会被公开。