【问题标题】:What is StringBuilder's RAM consumption like?StringBuilder 的 RAM 消耗情况如何?
【发布时间】:2010-02-12 17:45:50
【问题描述】:

我们有一些操作正在执行大量的大字符串连接,并且最近遇到了内存不足的异常。不幸的是,调试代码不是一种选择,因为这是在客户站点发生的。

所以,在对我们的代码进行大修之前,我想问一下:对于大字符串,StringBuilder 的 RAM 消耗特性是什么?

尤其是与标准字符串类型相比。字符串的大小远远超过 10 MB,我们似乎遇到了 20 MB 左右的问题。

注意:这与速度无关,而是 RAM。

【问题讨论】:

    标签: .net stringbuilder ram


    【解决方案1】:

    每次 StringBuilder 用完空间时,它都会重新分配一个两倍于原始缓冲区大小的新缓冲区,复制旧字符,并让旧缓冲区进行 GC'd。您可能只是使用了足够的(称为 x),以至于 2x 大于您允许分配的内存。您可能想要确定字符串的最大长度,并将其传递给 StringBuilder 的构造函数,以便您进行预分配,并且您不会受到双倍重新分配的支配。

    【讨论】:

      【解决方案2】:

      这是一个关于String Concatenation vs Memory Allocation 的很好的研究。

      如果可以避免串联,那就去做吧!

      如果你不这样做,这是没有道理的 必须连接但想要你的 源代码看起来不错,使用 第一种方法。它将被优化为 如果是单个字符串。

      永远不要使用 += 连接。正在发生太多变化 幕后,这并不明显 首先来自我的代码。我 建议宁可使用 String.Concat() 显式地与任何重载(2 字符串,3 个字符串,字符串数组)。 这将清楚地显示您的代码 没有任何意外,而 让自己保持检查 效率。

      尝试估计 StringBuilder 的目标大小。

      您可以估算的越准确 所需大小,临时性越小 StringBuilder 必须的字符串 创建以增加其内部 缓冲区。

      当性能成为问题时,不要使用任何 Format() 方法。

      涉及太多开销 解析格式,当你可以的时候 当 您正在使用的只是 {x} 替换。 Format() 有利于可读性,但是 当你在的时候要做的事情之一 挤出所有可能的表现 您的应用程序。

      【讨论】:

        【解决方案3】:

        您可能对绳索数据结构感兴趣。这篇文章:Ropes: Theory and practice 解释了它们的优势。也许有一个 .NET 的实现。

        [更新,回答评论] 它使用更少的内存吗?在文章中搜索内存,你会发现一些提示。
        基本上,是的,尽管有结构开销,因为它只是在需要时添加内存。 StringBuilder,当耗尽旧缓冲区时,必须分配一个更大的缓冲区(这已经浪费了空内存)并丢弃旧缓冲区(这将被垃圾收集,但同时仍然可以使用大量内存)。

        我还没有找到 .NET 的实现,但至少有一个 C++ 实现(在 SGI 的 STL 中:http://www.sgi.com/tech/stl/Rope.html)。也许你可以利用这个实现。请注意我参考的页面有关于内存性能的工作。

        请注意,绳索并不能解决所有问题:它们的实用性在很大程度上取决于您如何构建大弦以及如何使用它们。文章指出了优点和缺点。

        【讨论】:

        • 关于它如何执行 RAM 而非速度方面的任何数据?
        • 我通过更新我的回复来回答。我希望您收到有关 cmets 答案的通知。
        【解决方案4】:

        Srigbuilder 是一个完美的解决因连接字符串引起的内存问题的解决方案。

        为了回答您的具体问题,与字符串长度等于当前分配的 Stringbuilder 缓冲区长度的普通字符串相比,Stringbuilder 具有固定大小的开销。缓冲区可能是生成的字符串大小的两倍,但在连接到 Stringbuilder 时不会再分配内存,直到缓冲区被填满,所以这确实是一个很好的解决方案。

        与字符串相比,这是出色的。

        string output = "Test";
        output += ", printed on " + datePrinted.ToString();
        output += ", verified by " + verificationName;
        output += ", number lines: " + numberLines.ToString();
        

        这段代码有四个字符串作为文字存储在代码中,两个在方法中创建,一个来自变量,但它使用了六个独立的中间字符串,这些字符串越来越长。如果这种模式继续下去,它将以指数速度增加内存使用量,直到 GC 开始清理它。

        【讨论】:

          【解决方案5】:

          我不知道字符串生成器的确切内存模式,但通用字符串不是一个选项。

          当您使用公共字符串时,每个连接都会创建另外几个字符串对象,并且内存消耗猛增,导致垃圾收集器被频繁调用。

          string a = "a";
          
          //creates object with a
          
          a += "b"
          
          /creates object with b, creates object with ab, assings object with ab to "a" pointer
          

          【讨论】:

          • 我建议您在依赖它之前检查字符串类的实现。至少在 Java 中,它比现在更聪明。我没有检查过 .net 的实现,但我不明白他们为什么不做同样的优化。
          猜你喜欢
          • 1970-01-01
          • 2021-08-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-02
          • 1970-01-01
          • 2016-04-18
          相关资源
          最近更新 更多