【问题标题】:StringBuilder Class OutOfMemoryExceptionStringBuilder 类 OutOfMemoryException
【发布时间】:2011-11-24 03:59:22
【问题描述】:

我写了以下函数

public void TestSB()
{
  string str = "The quick brown fox jumps over the lazy dog.";
  StringBuilder sb = new StringBuilder();
  int j = 0;
  int len = 0;

  try
  {
     for (int i = 0; i < (10000000 * 2); i++)
     {
        j = i;
        len = sb.Length;
        sb.Append(str);
     }

    Console.WriteLine("Success ::" + sb.Length.ToString());
  }
  catch (Exception ex)
  {
      Console.WriteLine(
          ex.Message + " :: " + j.ToString() + " :: " + len.ToString());
  }
}

现在我想,StringBuilder 有能力处理超过 20 亿个字符(准确地说是 2,147,483,647)。

但是当我运行上述函数时,它在达到大约 8 亿的容量时给出了System.OutOfMemoryException。 此外,我在具有相同内存和相似负载量的不同 PC 上看到了截然不同的结果。

谁能提供或解释一下原因?

【问题讨论】:

标签: c# out-of-memory stringbuilder


【解决方案1】:

每个字符需要 2 个字节(因为 .NET 中的 char 是一个 UTF-16 代码单元)。因此,当您达到 8 亿个字符时,需要 1.6GB 的连续内存1。现在,当 StringBuilder 需要调整自身大小时,它必须创建 another 新大小的数组(我认为它试图将容量翻倍)——这意味着尝试分配一个 3.2GB 的数组。

相信 CLR(即使在 64 位系统上)不能分配大小超过 2GB 的单个对象。 (过去肯定是这样。)我的猜测是您的StringBuilder 正试图将大小翻倍,并打破了这个限制。您可以通过构建具有特定容量的StringBuilder 来获得更高的性能 - 大约十亿的容量可能是可行的。

在正常情况下,这当然不是问题 - 即使需要数百兆的字符串也很少见。


1 我相信StringBuilder 的实现实际上在.NET 4 中更改为在某些情况下使用片段-但我不知道细节。因此,它可能并不总是在仍处于构建器形式时需要连续内存......但如果你曾经调用过ToString,它会需要。

【讨论】:

  • 嗯,但是考虑到分配限制是由虚拟机而不是系统本身处理的,为什么这种行为会在不同的机器之间有所不同?
  • @Tigran:它可以基于两件事而有所不同:VM 实现(不同的主要版本,基于 CPU 架构的不同变化)和StringBuilder 本身的实现细节。哦,当然还有多少内存可用...
  • @Tigran 我认为是因为 StringBuilder 实际上需要 连续 内存来分配其内容,并且内存可以根据机器事先所做的事情以不同的方式进行分段。当仍有大量可用的物理 RAM 时,您仍然可能会出现 OutOfMemory 异常,因为没有足够的 连续 内存。
  • @jon 同意,但对我来说这听起来很奇怪,那个家伙说在具有明显相同配置的机器上得到非常不同的结果。但你实际上证实了我对机器平等的怀疑。
  • @atur: 对 - 与我的脚注相对应 - StringBuilder 的实现在 .NET 4 中发生了变化。
猜你喜欢
  • 2010-12-18
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-23
  • 2011-07-14
  • 2012-02-25
  • 2011-05-14
相关资源
最近更新 更多