c# - StringBuilder 类 OutOfMemoryException

标签 c# out-of-memory stringbuilder

我写了下面的函数

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 上看到了截然不同的结果。

谁能提供或解释一下这是什么原因?

最佳答案

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

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

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


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

关于c# - StringBuilder 类 OutOfMemoryException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7537795/

相关文章:

Android onPictureTaken 回调在 Bitmap.decodeByteArray 中抛出内存异常

java - 使用按钮从另一个类中的数组填充 JTextArea

Java int 数组到 StringBuilder

c# - 将可空引用类型转换为不可空引用类型,更简洁

c# - IDictionary<string, string> 与 Dictionary<string, string>

c# - 异步方法阻塞未等待的任务

Docker在构建时被系统杀死

memory-management - 在 XNA 中,处理我不再需要的纹理的最佳方法是什么?

c# - StringBuilder,如果满足条件追加字符串

c# - 闪烁的 ToolStripButton