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

前言

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

测试

1. int -> object

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

在这里插入图片描述
得出: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();
}

在这里插入图片描述
得出: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();
}

在这里插入图片描述

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

为了方便理解,我画了一个内存图
在这里插入图片描述

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();
}

在这里插入图片描述

  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;

在这里插入图片描述

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
    在这里插入图片描述
    在这里插入图片描述
    我们对比下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 + 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

在这里插入图片描述

结论

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

猜你喜欢

转载自blog.csdn.net/qq_52855744/article/details/126818425