在 C# 中,字符串是不可变引用类型,每次修改都会创建新实例,导致内存分配。要避免不必要的字符串分配,关键在于减少临时字符串的生成,优先使用结构化方式处理文本数据。
使用 Span 和 stackalloc
对于短字符串操作,可使用 Span
例如:
unsafe
{
char* buffer = stackalloc char[256];
// 填充数据到 buffer
string result = new string(buffer, 0, length);
}
使用 ReadOnlySpan 处理子串
传统 Substring() 会分配新字符串。改用 ReadOnlySpan
示例:
string input = "hello world"; ReadOnlySpan<char> span = input.AsSpan(); ReadOnlySpan<char> word = span.Slice(0, 5); // 不分配 // 后续处理可用 word 比较、查找等
使用 String.Create 预分配构造
当你必须创建新字符串但想控制分配时机,可用 String.Create:
提前指定长度,避免多次扩容 通过 Action示例:
string result = String.Create(10, 123, (chars, value) =>
{
// 直接写入 chars 指针
value.ToString().AsSpan().CopyTo(chars);
});
避免隐式字符串拼接
使用 StringBuilder 仍可能产生中间分配。更优选择包括:
用 string.Concat(params object[]) 替代多个 + 操作(如果参数少且固定) 对固定模板用 ReadOnlySpan 拼接后一次性转字符串 日志等场景考虑结构化输出,延迟字符串化基本上就这些。核心思路是:能不用字符串就先用 span,必须创建时尽量明确生命周期和大小,减少中间临时对象。配合 ref struct 和栈分配,能显著降低 GC 压力。
