如何解决StringBuilder的碎片化问题?

4
我在我的StringBuilders中遇到了一个好的SystemOutOfMemory异常。这不是由于缺乏RAM,因此我认为这是内存碎片化造成的。
我有大约200个StringBuilder对象。所有这些都经常重复使用(使用strBldr.clear())。这似乎导致我的系统内存严重碎片化。我该怎么解决这个问题?
谢谢 :)
编辑:
以下是一些数据:
输入和stringBuilder的最大记录大小:4 146 698。
每秒平均重新初始化的stringBuilders数量:>120(可能>>120)
第一个出错时的输入长度:16,972(字符串)
StringBuilder长度@第一个错误:16
第一个错误时新建StringBuilder的次数:~32500
第一个错误时总内存使用量为637 448K

我正在一台16 GB内存的机器上运行程序,而且该程序最大只占用了700 MB(任务管理器)。因此,我得出结论这不是内存不足导致的。 - Automatico
2
是的,那是总共的RAM。如果超过可分配给单个StringBuilder实例的内存量怎么办?请查看MSDN上的备注:"当实例的值被扩大并且容量相应地调整时,StringBuilder可以根据需要分配更多的内存来存储字符。分配的内存量是特定于实现的,如果所需内存量大于最大容量,则会抛出ArgumentOutOfRangeException或OutOfMemoryException异常。 - Cody Gray
@Cody,您上面的两条评论会成为一个好答案,您觉得呢? :) - Frédéric Hamidi
@Frederic:我没有将它们发布为答案,因为它们并没有真正解释如何解决问题。 - Cody Gray
显示剩余4条评论
3个回答

4
你不应该像那样重复使用一个StringBuilder,需要时只需创建一个新的。
当你在一个StringBuilder上调用Clear时,它不会释放所有已使用的内存,只会将已使用的大小重置为零。它仍然拥有相同的大缓冲区,而反复使用StringBuilder只意味着缓冲区将像以前一样大,并且永远不会缩小。
此外,保留StringBuilder对象以供重用意味着它们会经历垃圾回收并移动到下一代堆。这些堆更少地被收集,因此更可能对内存碎片敏感。

4

我同意,你很可能没有用完内存而是遇到了碎片化。

你需要了解什么是碎片化和大对象堆(LOH)。

由于你没有提供任何细节,所以我只能给出一些非常广泛的建议:

  • 尝试估计你的字符串有多大,并在创建新的SB时使用Capacity参数
  • 将这些大小向上舍入(真的),使它们成为某个数字的倍数。这样可以促进重复使用。
  • 只有在你期望新内容几乎与旧内容相同的情况下才使用Clear(),增长是杀手。

编辑

输入和stringBuilder的最大记录大小:4 146 698。

  • 确保不需要更大的中间件,然后
  • sb1 = new StringBuilder(4200000);这样创建所有的StringBuilder。
  • 不要尝试过度/完全重复使用它们
  • 不要让它们存在太长时间

当你说:“不要将它们保留太久”时,是指我应该将stringbuilder设置为null吗? - Automatico
很难给出如此广泛的建议。将本地变量置空是没有意义的,将字段置空可能是有用的。只需尽可能缩短它们的作用域即可。 - H H

0
我最终做的是迁移到x64。这解决了我的问题。
我可能实际上分配了整个x86的内存空间,即使我没有使用它全部。迁移到x64肯定会解决这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接