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

因此,在研究代码的大修之前,我想问一下:StringBuilder对大字符串的RAM消耗特性是什么?

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

注意:这不是速度而是RAM。

其他提示

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

您可能对绳索数据结构感兴趣。本文: Ropes:理论与实践解释了它们的优点。也许.NET有一个实现。

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

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

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

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

要回答您的具体问题,Stringbuilder与普通字符串相比具有恒定大小的开销,其中字符串的长度等于当前分配的Stringbuilder缓冲区的长度。缓冲区的大小可能是结果字符串的两倍,但在连接到Stringbuilder之前不会再进行内存分配,直到填充缓冲区为止,因此它确实是一个很好的解决方案。

与字符串相比,这很出色。

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

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

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

当你使用公共字符串时,每个连接都会创建另外两个字符串对象,并且内存消耗也会飙升,这使得垃圾收集器的调用过于频繁。

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top