用于字符串连接的StringBuilder抛出OutOfMemoryException

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

看看String vs StringBuilder

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

一些链接供参考StringBuilder OutOfMemoryException

而且还有更多……

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

有什么我想念的吗?

PS:我没有意识到这一点。

我已经改写了这个问题。

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

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

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

编辑以回应澄清:

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

使用StringBuilder还会导致所需内存的临时倍增,因为字符串将在System.Stringforms和StringBuilder中同时存在一小段时间。

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

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

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

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

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

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

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

  1. 不要一次将数据保存在内存中,将其放在磁盘上或其他东西上
  2. 将其分解,保留一个字符串/字符串构建器列表,并在切换到新的字符串之前将其添加到一定长度,以防止出现“连续内存”问题
  3. 重构算法根本不在内存中建立数十亿字节的数据

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

如果你看一下StringBuilder是如何实现的,你会发现它实际上使用一个String来保存数据( String有内部方法,这将允许StringBuilder在适当的位置进行修改)。

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

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

这个问题甚至会影响System.String类,所以你应该把你的输入块化为List 并并行处理数据,如果写得正确,这应该会提高整体性能。

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

我有一个非常相似的经验,我附加字符串,但忘了添加String.Format。 从而:

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

本来应该:

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

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

 myStringBuilder.Append('a', 1564544656); 

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

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

我希望能有所帮助。