用于字符串连接的 StringBuilder 抛出 OutOfMemoryException
-
21-08-2019 - |
题
我们大多倾向于遵循上述最佳实践。
但 StringBuilder 可能会抛出 即使有足够的可用内存,也会出现 OutOfMemoryException. 。它抛出 OOM 异常,因为它需要“连续的内存块”。
一些链接供参考StringBuilder 内存不足异常
还有更多......
你们中有多少人面临或意识到这个问题,你们采取了什么措施来解决这个问题?
我有什么遗漏的吗?
附:我不知道这一点。
我已经重新表述了这个问题。
*** 同样的事情也适用于手动连接(我将验证这一点并更新SO)。另一件让我担心的事情是系统中有足够的内存。这就是我在这里提出这个问题的原因,以检查是否有人遇到过这个问题或者代码存在严重错误。
解决方案
创建的underyling串还需要一个连续的内存块,因为它被表示为字符数组(阵列需要连续的存储器)。如果StringBuilder的抛出OOM异常你woludn't能够建立底层没有它。
如果创建一个字符串导致OOM,有可能是在你的应用更严重的问题。
编辑响应于澄清:
有是的情况下,当手动级联成功建立一个字符串一个StringBuilder将失败的一小部分。手动拼接将使用以两个字符串结合而一个StringBuilder已分配内存不同algorithmn所需的精确长度。这是更积极,将可能分配比实际需要的字符串更多的内存。
使用一个StringBuilder也将导致由于串将存在于以System.String形式和StringBuilder的同时在短时间内所需要的存储器的临时增加一倍。
但是,如果一个方法是引起OOM,另一个则不然,它仍可能指向你的程序更严重的问题。
其他提示
如果StringBuilder的是要扔在你的特殊情况一个OutOfMemoryException,然后做手工字符串连接是不是一个更好的解决方案;它差很多。这正是StringBuilder的是应该使用的情况下(产生极,极长的字符串)。字符串的手动拼接这个大会采取多次与StringBuilder的字符串的建立将占用内存。
这是说,一个现代化的电脑上,如果你的字符串的运行的计算机进行连续的内存的设计是深深地,深深地缺陷。我无法想象你可能这样做会创建一个字符串那么大。
我们谈论的是多少内存?我不是在谈论系统中的可用内存或总内存,而是您要连接的字符串有多长?
内存溢出异常几乎总是关于代码的一个非常糟糕的迹象,即使它在内存实际耗尽之前很久就失败了,就像您由于连续内存不可用而经历的那样。
那时你应该真正重构代码。
例如,以下是解决该问题的多种方法:
- 不要一次在内存中保留尽可能多的数据,将其放在磁盘或其他东西上
- 将其分解,保留字符串/字符串生成器列表,并且仅在切换到新字符串之前将它们添加到一定长度,从而避免“连续内存”问题
- 重构算法以根本不在内存中建立千兆字节的数据
如果您运行的是如此接近你的内存限制,这是连关心,那么你或许应该考虑不同的体系结构或得到一个比较强大的机器。
如果你看看StringBuilder
是如何实现的,你会看到,它实际上采用的是String
来保存数据(String
具有内部方法,这将允许StringBuilder
到位修改)。
即。它们都使用相同的内存量。然而,由于StringBuilder
将自动延伸的底层阵列并在需要时(但加倍容量)作为必要复制是最有可能的内存不足的错误的原因。但如其他人已经指出,两者的需要连续的存储器块,
好了,这个问题其实就是,你为什么需要那么长时间处理字符串的工作?如果你偶然发现这个问题,更可能你应该改变你的观念。
这个问题甚至影响的 System.String 的类,所以你还是块你输入列表<字符串> 的和并行处理数据,应该整体提高如果写入正确的性能。
我遇到了这个例外有sucessively不同stringbuilders(应该不会造成问题,因为他们是匿名函数内声明)建立了非常大的字符串,最后通过重用一个StringBuilder的,匿名函数的外部声明解决了这个问题。
我有我在那里追加字符串非常相似的经历,但忘了加上的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#中同样的问题)。
我希望可以帮助别人。