String 和 StringBuilder 消耗的内存是重复的

Memory consumed by String and StringBuilder is duplicate

我需要连接几个字符串。我正在为此使用 StringBuilder

        StringBuilder result = new StringBuilder(length);

最后的长度是我想要的字符串的"length"。

"Length" 的数字更大。 要获取字符串,我需要做

        return result.ToString();

当我尝试分析我的应用程序消耗的内存时,我发现 "StringBuilder" 和 "String" 正在占用相同数量的内存及其副本。 由于字符串长度较长,占用内存的百分比较大。

有没有更好的方法来解决这个内存问题?

解决什么内存问题?您已经观察到 行为,但没有解释问题所在。

请注意,在语句 return result.ToString(); 执行后,result 引用的 StringBuilder 对象立即符合垃圾回收条件(假设这是对该对象的唯一引用)。因此,任何理论问题都应该是暂时的,可能的结果很少或没有实际影响。

换句话说:假设您构建了 100 个长度为 N 的字符串。这些字符串的标称开销为每个字符两个字节,因此内存成本为 200 * N。在构建这些字符串的整个过程中,额外 StringBuilder 对象的标称内存成本是 N。是的,它可能同时存在多个对象,但 仅当它无关紧要时 。否则,.NET 会垃圾收集旧的,为新的腾出空间。

所以你的最终结果是额外 StringBuilder 的开销为 1%,比你的问题暗示的内存加倍要少得多。那就是如果您只构建 100 个字符串。有效开销与您实际创建的字符串数量成反比,当然开销的重要性 直接 与相同的数字成正比。换句话说,越重要,实际影响越小。


更一般地说,你认为你会找到什么样的选择? StringBuilder class 是处理可变字符串的最佳方式,即提供一种从部分创建字符串或以其他方式编辑字符串(例如从中删除部分、重新排列等)的方法.).也就是说,您可以实现自己的字符串编辑 class 以专门的方式实现类似的效果。

但是不管你用什么来编辑字符串,如果你在完成后想要一个 System.String 的实例,你就必须在字符串中有两个数据副本:一个在可编辑版本中,一个在最终 System.String 对象中。您不能编辑 System.String 对象(类型是不可变的),也不能神奇地将其他类型就地转换为 System.String.

的实例


(尽管顺便说一句,我会注意到在 StringBuilder 的旧实现中,来自 StringBuilder 的缓冲区实际上只是作为 reference 复制到新的 System.String 对象。没有创建字符串数据的新副本,除非在调用 ToString() 之后的某个时刻再次修改了 StringBuilder 对象。StringBuilder 的当前实现虽然不这样做。它针对涉及较长字符串的场景进行了优化,避免了 "double the buffer size" 重新分配成本,但始终需要为最终 ToString() 调用复制数据。


现在,如果您可以容忍使用字符串数据作为原始编辑对象(即 StringBuilder 或其他一些自定义 class)并且从不将数据转换为 System.String 的实例,那么这显然是一种避免数据二次拷贝的方法。在这种方法中,您永远不会为 ToString() 调用而烦恼。曾经。

但除此之外,您似乎在要求不可能的事情,因为没有可用的机制来获取现有的字符缓冲区并强制 System.String 使用该缓冲区作为其内部表示。 IE。在将任何其他数据结构(包括 StringBuilder)转换为 System.String 实例的过程中,将生成该数据的第二个副本是固有的。