- 前言
- 测试
- 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字符串拼接深入分析
private void Update()
{
int num = 1;
Profiler.BeginSample("int -> object");
object o = num;
Profiler.EndSample();
}
得出:int -> object 需要20B的内存
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的内存
3. 空string + intTips:ToString内部其实是new一个新的字符串,所以会有垃圾产生
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();
}
- 28B:ToString需要28B
- 20B:由于Concat需要object参数,所以int转object需要20B
为了方便理解,我画了一个内存图
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();
}
- 34B:tmp_str_3所占的空间:34B
- 28B:ToString需要28B
- 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();
}
- 34B:tmp_str_4所占的空间:34B
- 28B:ToString需要28B
我们对比下4和5,我们发现主动调用ToString可以避免装箱带来的GC。
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方法
- 34B:tmp_str_4所占的空间:34B
- 28B:a.ToString方法中的age.ToString需要28B
- 32B:struct装箱需要32B
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();
}
}
- 34B:tmp_str_4所占的空间:34B
- 28B:a.ToString方法中的age.ToString需要28B
我们在进行字符串拼接的时候,一定要手动调用ToString方法
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)