Подтвердить что ты не робот

С# Stringbuilder OutOfMemoryException

Я написал следующую функцию

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());
  }
}

Теперь я полагаю, что стробоструйщик имеет возможность взять более 2 миллиардов символов (точнее, 2 147 483 647).

Но когда я запускал указанную выше функцию, она давала "System.OutOfMemoryException" только при достижении емкости около 800 миллионов. Более того, я вижу совершенно другой результат на разных компьютерах, имеющих такую ​​же память и аналогичную нагрузку.

Может кто-нибудь объяснить или объяснить мне причину этого.

4b9b3361

Ответ 1

Для каждого символа требуется 2 байта (в качестве char в .NET - код кода UTF-16). Таким образом, к тому времени, когда вы достигли 800 миллионов символов, требуется 1,6 ГБ непрерывной памяти 1. Теперь, когда StringBuilder нуждается в изменении размера, он должен создать другой массив нового размера (который, как я полагаю, пытается удвоить емкость), что означает попытку выделить массив 3,2 ГБ.

Я считаю, что CLR (даже в 64-битных системах) не может выделить один объект размером более 2 ГБ. (Это, конечно, имело место.) Я предполагаю, что ваш StringBuilder пытается удвоить размер и сдуть этот предел. Возможно, вы сможете получить немного больше, построив StringBuilder с определенной пропускной способностью - возможно, будет возможно около миллиарда.

В нормальном ходу вещей это не проблема, конечно - даже строки, требующие сотни мегабайт, редки.


1 Я полагаю, что реализация StringBuilder фактически изменилась в .NET 4, чтобы использовать фрагменты в некоторых ситуациях, но я не знаю деталей. Таким образом, он может не всегда нуждаться в непрерывной памяти, но все еще в форме строителя... но это было бы, если бы вы когда-либо звонили ToString.