16

我们大多倾向于遵循上述最佳实践。

看看String 与 StringBuilder

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

一些链接供参考 StringBuilder OutOfMemoryException

还有更多......

你们中有多少人面临或意识到这个问题,你做了什么来解决它?

有什么我想念的吗?

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

我已经改写了这个问题。

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

4

8 回答 8

19

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

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

编辑以回应澄清:

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

使用 StringBuilder 还将导致所需内存临时加倍,因为字符串将在短时间内以 System.String 形式和 StringBuilder 同时存在。

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

于 2008-12-12T18:24:41.553 回答
4

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

也就是说,在现代计算机上,如果您的字符串在连续内存不足的情况下运行计算机,则您的设计存在严重缺陷。我无法想象你可能会做什么来创建一个那么大的字符串。

于 2008-12-12T18:33:22.957 回答
3

我们在谈论多少内存?我不是在谈论系统中的可用内存或总内存,但是您要连接的字符串有多长?

内存溢出异常几乎总是关于您的代码的一个非常糟糕的信号,即使它在内存实际耗尽之前很久就失败了,就像您由于连续内存不可用而经历的那样。

那时你真的应该重构代码。

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

  1. 不要一次将尽可能多的数据保存在内存中,将其放在磁盘或其他东西上
  2. 分解它,保留一个字符串/字符串生成器列表,并且在切换到新的之前只添加到一定长度,避免“连续内存”问题
  3. 重构算法以完全不在内存中建立千兆字节的数据
于 2008-12-12T18:50:40.457 回答
2

如果您的内存限制如此接近以至于这甚至是一个问题,那么您可能应该考虑不同的架构或获得更强大的机器。

于 2008-12-12T18:29:49.670 回答
2

如果您查看StringBuilder其实现方式,您会发现它实际上使用 aString来保存数据(String具有内部方法,允许StringBuilder就地修改)。

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

于 2008-12-12T19:29:58.317 回答
1

好吧,问题实际上是,为什么你需要处理这么长的字符串?如果你偶然发现了这个问题,你很可能应该改变你的概念。

这个问题甚至会影响System.String类,因此您应该将输入分块到List<string>并并行处理数据,如果编写得当,这应该会提高整体性能。

于 2008-12-12T18:33:08.370 回答
0

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

于 2011-09-17T22:27:31.403 回答
0

我有一个非常相似的经验,我在附加字符串但忘记添加 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# 中并行处理完全相同的问题)。

我希望这对某人有所帮助。

于 2011-12-22T21:32:00.900 回答