性能优化--string 字符串拼接(超详细)

目录

      • 前言
      • 测试
        • 1. int -> object
        • 2. int.ToString()
        • 3. 空string + int
        • 4. 非空string + int
        • 5. 非空string + int.ToString
      • 非空string + struct
      • 非空string + struct.ToString
      • 结论

前言

本文章需要了解前缀知识
C# string为什么可以与int相加? string字符串拼接深入分析

测试

1. int -> object

private void Update()
{
    int num = 1;
    Profiler.BeginSample("int -> object");
    object o = num;
    Profiler.EndSample();
}

性能优化--string 字符串拼接(超详细)_第1张图片
得出:int -> object 需要20B的内存

2. int.ToString()

private void Update()
{
    int num = 1;
    Profiler.BeginSample("int -> object");
    object o = num;
    Profiler.EndSample();

	Profiler.BeginSample("int ToString()");
    string tmp_str_1 = num.ToString();
    Profiler.EndSample();
}

性能优化--string 字符串拼接(超详细)_第2张图片
得出:int 调用ToString 需要28B的内存

Tips:ToString内部其实是new一个新的字符串,所以会有垃圾产生

3. 空string + int

private void Update()
{
    int num = 1;
    Profiler.BeginSample("int -> object");
    object o = num;
    Profiler.EndSample();

	Profiler.BeginSample("int ToString()");
    string tmp_str_1 = num.ToString();
    Profiler.EndSample();

	Profiler.BeginSample("Empty string + int");
    string tmp_str_2 = "";
    tmp_str_2 += num;
    Profiler.EndSample();
}

性能优化--string 字符串拼接(超详细)_第3张图片

  1. 28B:ToString需要28B
  2. 20B:由于Concat需要object参数,所以int转object需要20B

为了方便理解,我画了一个内存图
性能优化--string 字符串拼接(超详细)_第4张图片

4. 非空string + int

private void Update()
{
    int num = 1;
    Profiler.BeginSample("int -> object");
    object o = num;
    Profiler.EndSample();

	Profiler.BeginSample("int ToString()");
    string tmp_str_1 = num.ToString();
    Profiler.EndSample();

	Profiler.BeginSample("Empty string + int");
    string tmp_str_2 = "";
    tmp_str_2 += num;
    Profiler.EndSample();

    Profiler.BeginSample("Not Empty string + int");
    string tmp_str_3 = "123";
    tmp_str_3 = tmp_str_3 + num;
    Profiler.EndSample();
}

性能优化--string 字符串拼接(超详细)_第5张图片

  1. 34B:tmp_str_3所占的空间:34B
  2. 28B:ToString需要28B
  3. 20B:由于Concat需要object参数,所以int转object需要20B

注意
为什么这里多了一个34B呢?之前空字符串为什么没有多?

因为tmp_str_2是空字符串,所以编译器做了处理。

string tmp_str_2 = "";
tmp_str_2 += num;

等价于

string tmp_str_2 = num;//注意:这里是伪代码,因为int不能直接转string,底层应该是先装箱,再ToString

所以空字符串相加是 20 + 28 = 48B

所以非空string + int的内存图应该是这样的

string tmp_str_3 = "123";
tmp_str_3 = tmp_str_3 + num;

性能优化--string 字符串拼接(超详细)_第6张图片

5. 非空string + int.ToString

private void Update()
{
    int num = 1;
    Profiler.BeginSample("int -> object");
    object o = num;
    Profiler.EndSample();

	Profiler.BeginSample("int ToString()");
    string tmp_str_1 = num.ToString();
    Profiler.EndSample();

	Profiler.BeginSample("Empty string + int");
    string tmp_str_2 = "";
    tmp_str_2 += num;
    Profiler.EndSample();

    Profiler.BeginSample("Not Empty string + int");
    string tmp_str_3 = "123";
    tmp_str_3 = tmp_str_3 + num;
    Profiler.EndSample();

	Profiler.BeginSample("Not Empty string + int.ToString");
    string tmp_str_4 = "123";
    tmp_str_4 = tmp_str_4 + num.ToString();
    Profiler.EndSample();
}
  1. 34B:tmp_str_4所占的空间:34B
  2. 28B:ToString需要28B
    性能优化--string 字符串拼接(超详细)_第7张图片
    性能优化--string 字符串拼接(超详细)_第8张图片
    我们对比下4和5,我们发现主动调用ToString可以避免装箱带来的GC。

非空string + struct

private void Update()
{
    int num = 1;
    Profiler.BeginSample("int -> object");
    object o = num;
    Profiler.EndSample();

	Profiler.BeginSample("int ToString()");
    string tmp_str_1 = num.ToString();
    Profiler.EndSample();

	Profiler.BeginSample("Empty string + int");
    string tmp_str_2 = "";
    tmp_str_2 += num;
    Profiler.EndSample();

    Profiler.BeginSample("Not Empty string + int");
    string tmp_str_3 = "123";
    tmp_str_3 = tmp_str_3 + num;
    Profiler.EndSample();

	Profiler.BeginSample("Not Empty string + int.ToString");
    string tmp_str_4 = "123";
    tmp_str_4 = tmp_str_4 + num.ToString();
    Profiler.EndSample();

	A a = new A(5, "A");
    Profiler.BeginSample("Not Empty string + struct");
    string tmp_str_5 = "123";
    tmp_str_5 = tmp_str_5 + a;
    Profiler.EndSample();
}

public struct A
{
    public int age;
    public string name;
    public A(int age, string name)
    {
        this.age = age;
        this.name = name;
    }
    public override string ToString()
    {
        return age.ToString();
    }
}

Tips:结构体是值类型,所以要先装箱,然后再调用内部实现的ToString方法

  1. 34B:tmp_str_4所占的空间:34B
  2. 28B:a.ToString方法中的age.ToString需要28B
  3. 32B:struct装箱需要32B

性能优化--string 字符串拼接(超详细)_第9张图片

性能优化--string 字符串拼接(超详细)_第10张图片

非空string + struct.ToString

private void Update()
{
    int num = 1;
    Profiler.BeginSample("int -> object");
    object o = num;
    Profiler.EndSample();

	Profiler.BeginSample("int ToString()");
    string tmp_str_1 = num.ToString();
    Profiler.EndSample();

	Profiler.BeginSample("Empty string + int");
    string tmp_str_2 = "";
    tmp_str_2 += num;
    Profiler.EndSample();

    Profiler.BeginSample("Not Empty string + int");
    string tmp_str_3 = "123";
    tmp_str_3 = tmp_str_3 + num;
    Profiler.EndSample();

	Profiler.BeginSample("Not Empty string + int.ToString");
    string tmp_str_4 = "123";
    tmp_str_4 = tmp_str_4 + num.ToString();
    Profiler.EndSample();

	A a = new A(5, "A");
    Profiler.BeginSample("Not Empty string + struct");
    string tmp_str_5 = "123";
    tmp_str_5 = tmp_str_5 + a;
    Profiler.EndSample();

    Profiler.BeginSample("Not Empty string + struct.ToString");
    string tmp_str_6 = "123";
    tmp_str_6 = tmp_str_6 + a.ToString();
    Profiler.EndSample();
}

public struct A
{
    public int age;
    public string name;
    public A(int age, string name)
    {
        this.age = age;
        this.name = name;
    }
    public override string ToString()
    {
        return age.ToString();
    }
}
  1. 34B:tmp_str_4所占的空间:34B
  2. 28B:a.ToString方法中的age.ToString需要28B

性能优化--string 字符串拼接(超详细)_第11张图片

结论

我们在进行字符串拼接的时候,一定要手动调用ToString方法

你可能感兴趣的:(C#,性能优化,性能优化,c#,c++)