C # Stringbuilder OutOfMemoryException - PullRequest
       24

C # Stringbuilder OutOfMemoryException

18 голосов
/ 24 сентября 2011

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

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 способен принимать более 2 миллиардов символов (точнее, 2 147 483 647).

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

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

1 Ответ

33 голосов
/ 24 сентября 2011

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

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

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


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

...