String连接的StringBuilder抛出OutOfMemoryException

时间:2008-12-12 18:20:42

标签: c# out-of-memory stringbuilder

我们大多倾向于遵循上述最佳做法。

查看String vs StringBuilder

但即使有足够的可用内存,StringBuilder也可能抛出 OutOfMemoryException 。它抛出OOM异常,因为它需要“连续的内存块”。

一些链接供参考 StringBuilder OutOfMemoryException

还有更多......

你们中有多少人遇到过这个问题或意识到你们做了什么来解决这个问题?

我有什么遗失的吗?

P.S:我没有意识到这一点。

我已经改写了这个问题。

***同样适用于手动连接(我将验证并更新SO)。引起我担忧的另一件事是系统中有足够的内存。这就是我在这里提出这个问题的原因,以检查是否有人遇到这个问题或者代码有什么严重错误。

8 个答案:

答案 0 :(得分:18)

您创建的underyling字符串还需要一个连续的内存块,因为它表示为chars数组(数组需要连续的内存)。如果StringBuilder抛出一个OOM异常,你将无法在没有它的情况下构建底层。

如果创建字符串会导致OOM,则应用程序中可能存在更严重的问题。

编辑以回应澄清:

有一小部分情况,当手动连接成功时,使用StringBuilder构建字符串将失败。手动连接将使用所需的确切长度以组合两个字符串,而StringBuilder具有用于分配内存的不同算法。它更具侵略性,可能会分配比字符串实际需要的内存更多的内存。

使用StringBuilder还会导致所需内存暂时加倍,因为字符串将在System.String形式和StringBuilder中同时出现一小段时间。

但是,如果一种方式导致OOM而另一种方式不是,那么它仍可能指向您的程序中更严重的问题。

答案 1 :(得分:4)

如果StringBuilder将在您的特定情况下抛出OutOfMemoryException,那么进行手动字符串连接不是更好的解决方案;这更糟糕。这正是使用StringBuilder的情况(创建一个非常非常长的字符串)。手动连接一个字符串,这个字符串将占用StringBuilder创建字符串所需的内存很多次。

也就是说,在现代计算机上,如果你的字符串是从连续的内存中运行计算机,那么你的设计就会深深地陷入其中。我无法想象你能做什么会产生一个很大的字符串。

答案 2 :(得分:3)

我们谈论了多少记忆?我不是在谈论系统中的空闲或总内存,但是你连接的字符串有多长?

内存溢出异常对于你的代码来说几乎总是一个非常糟糕的标志,即使它在内存实际耗尽之前很久就会失败,就像你因为连续内存不可用而经历过。

此时你应该重新构建代码。

例如,以下是解决问题的各种方法:

  1. 一次不要在内存中保留尽可能多的数据,将其放在磁盘上或其他东西
  2. 分解它,保留一个字符串/字符串构建器列表,只在添加到一定长度之前再切换到新的字符串/字符串构建器,保持“连续内存”问题。
  3. 重构算法,以便在内存中不会累积数GB的数据

答案 3 :(得分:2)

如果您查看StringBuilder的实施方式,您会发现它实际上使用String来保存数据(String有内部方法,这将允许{{1}在适当的地方修改)。

即。他们都使用相同数量的内存。但是,由于StringBuilder将自动扩展底层数组并在需要时复制(但容量增加一倍),这很可能是内存不足错误的原因。但正如其他人已经指出这两者都要求连续的内存块,

答案 4 :(得分:2)

如果你的行程如此接近你的记忆限制,这甚至是一个问题,那么你应该考虑一个不同的架构或获得更强大的机器。

答案 5 :(得分:1)

嗯,问题实际上是,为什么你需要长时间处理字符串?如果你偶然发现这个问题,你很可能会改变你的观念。

这个问题甚至会影响 System.String 类,所以你应该把你的输入分成 List<字符串> 并且并行处理数据,如果写得正确,这应该会提高整体性能。

答案 6 :(得分:0)

我有一个非常相似的经历,我在附加字符串,但忘了添加String.Format。因此:

myStringBuilder.Append("1,""{0}""", someVeryLargeIntVariable)

应该是:

myStringBuilder.Append(String.Format("1,""{0}""", someVeryLargeIntVariable))

请注意,这是我失败的vb.net代码。我在c#中复制了一个类似的测试:

myStringBuilder.Append('a', 1564544656);

VS

myStringBuilder.Append(string.Format("1,\"{0}\"", 1564544656));

但在我的情况下,vb.net让我陷入了隐式转换的麻烦b / c(我无法在c#中与完全相同的问题并行)。

我希望能帮助别人。

答案 7 :(得分:0)

我遇到了这个异常,非常大的字符串是用不同的字符串构建器构建的(这不应该导致问题,因为它们是在匿名函数中声明的),最后通过重用在匿名函数之外声明的单个StringBuilder来解决它。

豫ICP备18024241号-1