C#常考随笔2:函数中多次使用string的+=处理,为什么会产生大量内存垃圾(垃圾碎片),有什么好的方法可以解决?
在 C# 中,由于string
类型是不可变的,当在函数中多次使用+=
操作符来拼接字符串时,每次操作都会创建一个新的string
对象,旧的对象则成为垃圾对象,这会导致大量的内存分配和垃圾回收,产生内存垃圾和碎片。
在需要多次拼接字符串的场景中,优先使用StringBuilder
类,并根据情况预分配容量,或者使用string.Join
方法,减少内存垃圾的产生。
1. 使用StringBuilder
类
StringBuilder
类是一个可变的字符串类型,它内部维护了一个字符数组,当需要追加字符串时,会在这个数组上进行操作,而不是像string
那样每次都创建新的对象。因此,使用StringBuilder
可以显著减少内存分配和垃圾回收的开销。
示例代码:
using System;
using System.Text;
class Program
{
static void Main()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
sb.Append(i.ToString());
}
string result = sb.ToString();
Console.WriteLine(result);
}
}
2. 预分配StringBuilder
的容量
在创建StringBuilder
对象时,可以预先指定其容量,这样可以避免在追加字符串时频繁地进行数组扩容操作,进一步提高性能。
示例代码:
using System;
using System.Text;
class Program
{
static void Main()
{
// 假设最终字符串长度大约为 5000
StringBuilder sb = new StringBuilder(5000);
for (int i = 0; i < 1000; i++)
{
sb.Append(i.ToString());
}
string result = sb.ToString();
Console.WriteLine(result);
}
}
3. 使用string.Join
方法
如果需要将一个字符串数组或集合中的元素拼接成一个字符串,可以使用string.Join
方法。string.Join
方法会根据元素的数量和长度预先计算所需的内存空间,然后一次性分配,避免了多次创建string
对象。
示例代码:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> stringList = new List<string>();
for (int i = 0; i < 1000; i++)
{
stringList.Add(i.ToString());
}
string result = string.Join("", stringList);
Console.WriteLine(result);
}
}