6

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

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

特别是当它们与标准字符串类型进行比较时。字符串的大小远远超过 10 MB,我们似乎遇到了大约 20 MB 的问题。

注意:这不是关于速度,而是关于 RAM。

4

5 回答 5

10

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

于 2008-09-29T16:47:17.257 回答
6

这是关于字符串连接与内存分配的一个很好的研究。

如果你可以避免连接,那就去做吧!

这很简单,如果您不必连接但希望源代码看起来不错,请使用第一种方法。它将像单个字符串一样得到优化。

永远不要使用 += 连接。幕后发生了太多的变化,这在我的代码中并不明显。我建议宁可将 String.Concat() 显式用于任何重载(2 个字符串、3 个字符串、字符串数组)。这将清楚地显示您的代码所做的事情,不会有任何意外,同时让您自己检查效率。

尝试估计 StringBuilder 的目标大小。

估计所需大小越准确,StringBuilder 为增加其内部缓冲区而必须创建的临时字符串就越少。

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

解析格式涉及太多开销,当您使用的所有内容都是 {x} 替换时,您可以构建一个由片段组成的数组。Format() 有利于提高可读性,但是当您从应用程序中挤出所有可能的性能时,这是要做的事情之一。

于 2008-09-29T17:54:34.380 回答
3

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

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

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

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

于 2008-09-29T19:28:38.007 回答
1

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

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

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

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

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

于 2008-09-29T17:20:42.713 回答
-2

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

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

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
于 2008-09-29T16:48:14.930 回答