最近学习了下IL,寻思着小试牛刀,学以致用嘛。
所以就拿值类型与字符串连接来作了几组测试,使用Unity的Profiler提供的BeginSample和EndSample查看GC和cpu耗时,先把结果展示出来。
一、字符串连接代码与Profile展示
1.直接使用"+"连接一次,值类型不调用ToString方法



2.直接使用"+"连接一次,值类型调用ToString方法



3.使用String.Format连接一次,值类型不调用ToString方法


4.使用String.Format连接一次,值类型调用ToString方法


5.使用StringBuilder连接一次(StringBuilder重载支持基本的值数据类型)


可以看出无论是使用"+"号连接还是使用String.Format方法,Time.time(值类型)没有调用ToString方法的,GC多出20B,cpu耗时都在0.01ms,无明显差别,StringBuilder因为重载了Append方法,可以看出与值类型的ToString后连接的方式GC一致。
接下来我们循环100次,再看看结果。
6.直接使用"+"连接100次,值类型不调用ToString方法


7.直接使用"+"连接100次,值类型调用ToString方法


8.使用String.Format连接100次,值类型不调用ToString方法


9.使用String.Format连接100次,值类型调用ToString方法


10.使用StringBuilder连接100次(StringBuilder重载支持基本的值数据类型)


循环100次与单独一次GC几乎是没有差异的,约等于乘以100,而在耗时上"+"连接与StringBuilder是一致,似乎比String.Format耗时更短,因耗时在百分之一毫秒级,这里不做深究,但是可以看出值类型与字符串连接时,值类型的ToString方法调用与否会影响GC的开销。
二、IL代码分析
我们再来看一下IL代码。





通过IL代码我们可以确定,额外的GC开销是因为值类型与字符串连接时,因为未调用ToString方法,会发生一次装箱操作,我们来看看String.Format方法的参数

参数是作为object传入,所以会先从值类型转换到object类型,将值从堆栈中copy到托管堆,新建一个object类型的数据,再执行字符串连接操作,而值类型调用ToString方法后,直接就可以执行字符串连接操作。
三、测试结果图表展示



四、结论
1.值类型在与字符串连接时,无论是"+"连接,还是String.Format方法当值类型没有调用ToString方法时,都会发生装箱操作,带来额外的GC开销(cpu耗时开销不明显)
2.为了避免不必要的开销,值类型在与字符串连接时,值类型应该先调用一下ToString方法,养成好习惯。
最后,我也看到有些文章提到其实没有必要手动ToString,首先消耗并不多,而且也影响代码的美观,不过我觉得性能应该是第一位,没有好的性能,再美观的代码,用户也不会认可,用户不会去关心代码优不优雅,美不美观,用户只关心app是不是耗电,是不是卡顿。
网友评论