【问题标题】:Memory consumed by String and StringBuilder is duplicateString 和 StringBuilder 消耗的内存是重复的
【发布时间】:2015-06-07 02:56:19
【问题描述】:

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

        StringBuilder result = new StringBuilder(length);

长度是我想要的字符串的“长度”。

“长度”是更大的数字。 要获取字符串,我需要做

        return result.ToString();

当我试图分析我的应用程序消耗的内存时,我看到“StringBuilder”和“String”占用了相同数量的内存及其副本。 由于字符串的长度很长,它占用的内存百分比更大。

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

【问题讨论】:

  • 在不知道您要解决的问题的情况下很难回答这个问题。但是如果你的应用程序因为大字符串而使用了太多内存,那么看起来你根本不应该使用字符串。那么流式传输方法可能会更好。
  • 是的,我们需要序列化它并且需要从另一端读取。所以我们使用字符串。
  • 好吧,如果你想使用字符串,那么你必须忍受后果。但是,如果您使用 StringBuilder 来连接已知(在编译时)数量的字符串,那么使用 + 运算符可能会更好,因为编译器会将其转换为 String.Concat 并且可能避免为临时对象。
  • 解决这个内存问题? 有问题吗?或者你只是有这么多的空闲内存垃圾收集器没有运行?

标签: c# .net string performance memory-leaks


【解决方案1】:

要解决什么内存问题?您观察到了一种行为,但没有解释它是什么问题。

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

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

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


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

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


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


现在,如果您可以容忍使用字符串数据作为原始编辑对象(即StringBuilder 或其他一些自定义类)并且从不将数据转换为System.String 的实例,那么这显然是避免第二个副本的方法数据。在这种方法中,您永远不会打扰ToString() 电话。永远。

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

【讨论】:

  • 感谢您的精彩解释。我希望我需要将数据类型从字符串更改为字节或其他一些数据类型。因为字符串只是用于从一个系统到另一个系统的通信。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-12
  • 2015-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多