StringBuilder比字符串拼接使用更多的内存吗?

12

我知道在C#中使用StringBuilder的明显性能优势,但它的内存差异如何?

StringBuilder是否使用更多的内存?作为一个附注,stringbuilder到底有什么不同的地方使它更快?

3个回答

18

简短回答: 当你需要连接一个数量未知的字符串并且在编译时无法确定这些字符串时,StringBuilder 是适当的选择。

如果你在编译时知道要连接哪些字符串,那么使用 StringBuilder 就没有必要了,因为你不需要它的动态调整大小的能力。

例如 1: 如果你想要连接 "cat", "dog" 和 "mouse" 这三个字符串,它们总共有11个字符。你可以简单地分配一个长度为11的 char[] 数组,并将这些字符串的字符填充到数组中。这基本上就是 string.Concat 所做的事情。

例如 2: 如果你想将未指定数量的用户提供的字符串连接成一个单一的字符串。由于要连接的数据量预先未知,因此在这种情况下使用 StringBuilder 是适当的。


16

StringBuilder并不一定更快。据我所知,如果你连接的字符串少于十个,字符串连接(无论是通过String.Concat还是简单的str1 + str2)实际上更快。原因是分配和初始化StringBuilder实际上需要时间。

StringBuilder更快的原因是它创建了一个内部缓冲区,将字符串添加到其中。如果您连接20个字符串,StringBuilder只需将一个接一个地附加到其缓冲区,最后在请求时返回结果-通过它的ToString()方法。 (我假设有足够的缓冲区空间。否则,StringBuilder会担心重新分配缓冲区,并具有帮助它不过多重新分配的启发式算法。)如果你连接的是字符串,每个字符串连接都会为长度为(str1.Length + str2.Length)的新字符串分配内存,并将第一个和第二个字符串复制到指定位置。这导致了大量的字符串重新复制。

var result = str1 + str2 + str3 + ... + strN;
这将需要N-1次分配和N-1次复制操作,对于大的N来说这可能会非常昂贵。请注意,您正在复制str1的内容N-1次。一次是为了得到str1+str2的结果。然后再次得到(str1+str2)+str3的结果。使用StringBuilder,只需要将每个字符串拷贝到内部缓冲区一次,假设缓冲区足够大以容纳各个字符串。

5
我认为你结束段落的前几句话是不正确的。以这种方式连接许多字符串的单行代码,除非我弄错了,将会编译成单个的string.Concat调用,它只需一次性分配足够结果字符串所需的空间,而不需要像你所暗示的那样进行多次重新分配。 - Dan Tao
C#编译器可能具有该优化。我还没有检查过。更多时候,这些类型的连接是在for循环内完成的,无法进行优化。C#编译器确实针对连接一系列常量字符串的情况进行了优化,这会导致编译器发出单个常量字符串并完全避免运行时连接。 - James Kovacs

5

我认为你真的应该阅读这篇文章:微优化剧院的悲惨悲剧,如果你要回答StringBuilder v/s Concat,可以在跳转后找到答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接