通过unity profiler测试的代码,及运行结果
using UnityEngine;
using UnityEngine.Profiling;
using System.Text;
#if UNITY_5_5_OR_NEWER
using TProfiler = UnityEngine.Profiling.Profiler;
#else
using TProfiler = UnityEngine.Profiler;
#endif
public namespace Test {
/// string concat test
public class TestString : MonoBehaviour {
// Update is called once per frame
void Update ()
{
// loop 10000times
for(int i = 0; i < 10000; ++i) {
TestString();
}
TestString10000();
}
// object new once
private StringBuilder _sb = new StringBuilder();
/// concat 10000 times
private void TestString10000() {
// +
TProfiler.BeginSample("string.(10000+)");
string s1 = string.Empty;
for(int i = 0; i < 10000; ++i) {
s1 = s1 + ((int)Time.time).ToString();
}
TProfiler.EndSample();
// StringBuilder Append
TProfiler.BeginSample("StringBuilder.10000Append");
_sb.Clear();
for(int i = 0; i < 10000; ++i) {
_sb.Append((int)Time.time);
}
string s2 = _sb.ToString();
TProfiler.EndSample();
}
/// concat 3 parts
private void TestString() {
System.Random random = new System.Random();
// +
TProfiler.BeginSample("string.(+)");
string s1 = "txt_pre_" + random.Next().ToString() + "_end";
TProfiler.EndSample();
// Concat
TProfiler.BeginSample("string.Concat");
string s2 = string.Concat("txt_pre_", random.Next(), "_end");
TProfiler.EndSample();
// Concat ToString()
TProfiler.BeginSample("string.Concat & int.ToString");
string s3 = string.Concat("txt_pre_", ((int)Time.time).ToString(), "_end");
TProfiler.EndSample();
// format
TProfiler.BeginSample("string.Format");
string s4 = string.Format("txt_pre_{0}_end", (int)Time.time);
TProfiler.EndSample();
// format ToString()
TProfiler.BeginSample("string.Format & int.ToString");
string s5 = string.Format("txt_pre_{0}_end", ((int)Time.time).ToString());
TProfiler.EndSample();
// StringBuilder AppendFormat
TProfiler.BeginSample("StringBuilder.AppendFormat & int.ToString");
_sb.Clear();
_sb.AppendFormat("txt_pre_{0}_end", ((int)Time.time).ToString());
string s6 = _sb.ToString();
TProfiler.EndSample();
// StringBuilder Append
TProfiler.BeginSample("StringBuilder.Append");
_sb.Clear();
_sb.Append("txt_pre_");
_sb.Append((int)Time.time);
_sb.Append("_end");
string s7 = _sb.ToString();
TProfiler.EndSample();
// StringBuilder Append ToString()
TProfiler.BeginSample("StringBuilder.Append & int.ToString");
_sb.Clear();
_sb.Append("txt_pre_");
_sb.Append(((int)Time.time).ToString());
_sb.Append("_end");
string s8 = _sb.ToString();
TProfiler.EndSample();
// StringBuilder AppendNumber
TProfiler.BeginSample("StringBuilder.AppendNumber");
_sb.Clear();
_sb.Append("txt_pre_");
_sb.AppendNumber((int)Time.time);
_sb.Append("_end");
string s9 = _sb.ToString();
TProfiler.EndSample();
}
}
}
运行结果:
结果分析及结论:
1、string.Format和StringBuider.AppendFormat()
- 可读性好
- 堆内存开销高,因为Format需要额外的内存分配
- 运行效率低
- 建议:
- 【少用,慎用】
2、StringBuilder.Append
- 可读性一般
- 堆内存开销低
- 运行效率较高
- 建议:
- 大量字符串拼接时【必须使用】,内存及运行效率优化效果十分明显
- 少量字符串拼接时【酌情使用】,如调用频度
3、+和Concat
- 可读性较好
- 堆内存开销低
- 运行效率较高
- 在很多情况下,+会被优化为Concat
- 建议:
- 大量字符串拼接时【禁止使用】,内存及运行效率开销非常大,无法忍受
- 少量字符串拼接时【建议使用】
另外,对于string拼接时的int等基本数据类型,养成ToString()的习惯,避免Box操作带来的额外内存开销。