StringBuilder для конкатенации строк создает исключение OutOfMemoryException - PullRequest
15 голосов
/ 12 декабря 2008

Мы в основном следуем приведенным выше рекомендациям.

Посмотрите на String vs StringBuilder

Но StringBuilder может выдать OutOfMemoryException, даже если имеется достаточно памяти . Выдает исключение OOM, потому что ему нужен "непрерывный блок памяти".

Некоторые ссылки для справки StringBuilder OutOfMemoryException

и есть еще много .....

Кто из вас сталкивался с этой проблемой или знал, и что вы сделали, чтобы решить ее?

Есть ли что-то, чего мне не хватает?

П.С.: Я не знал об этом.

Я перефразировал вопрос.

*** То же самое работало с ручной конкатенацией (я проверю это и обновлю SO). Другая вещь, которая вызывала у меня беспокойство, это то, что в системе достаточно памяти. Вот почему я поднял этот вопрос здесь, чтобы проверить, сталкивался ли кто-нибудь с этой проблемой, или в коде было что-то радикально неправильное.

Ответы [ 8 ]

18 голосов
/ 12 декабря 2008

Создаваемой вами подчиненной строке также потребуется непрерывный блок памяти, поскольку он представлен в виде массива символов (для массивов требуется непрерывная память). Если StringBuilder выдает исключение OOM, вы не сможете построить базовый объект без него.

Если создание строки вызывает OOM, вероятно, в вашем приложении есть более серьезная проблема.

Изменить в ответ на уточнение:

Существует небольшое подмножество случаев, когда построение строки с помощью StringBuilder завершится неудачно, когда конкатенация завершится успешно. Ручная конкатенация будет использовать точную длину, необходимую для объединения двух строк, в то время как StringBuilder имеет другой алгоритм для выделения памяти. Он более агрессивен и, вероятно, выделит больше памяти, чем на самом деле нужно для строки.

Использование StringBuilder также приведет к временному удвоению необходимой памяти, поскольку строка будет присутствовать в форме System.String и StringBuilder одновременно в течение короткого времени.

Но если один из способов вызывает OOM, а другой - нет, это все же, вероятно, указывает на более серьезную проблему в вашей программе.

4 голосов
/ 12 декабря 2008

Если StringBuilder собирается выдать исключение OutOfMemoryException в вашей конкретной ситуации, то ручное объединение строк НЕ является лучшим решением; это намного хуже. Это как раз тот случай (создание чрезвычайно длинной строки), где предполагается использовать StringBuilder. Ручная конкатенация такой большой строки займет много раз памяти, которая потребовалась бы для создания строки с помощью StringBuilder.

Тем не менее, на современном компьютере, если ваша строка работает на компьютере из смежной памяти ваш дизайн глубоко, глубоко испорчен. Я не могу представить, что вы могли бы сделать, чтобы создать такую ​​большую строку.

3 голосов
/ 12 декабря 2008

Сколько памяти мы говорим? Я не говорю о свободной или полной памяти в системе, но как долго соединяется строка, которую вы объединяете?

Исключение переполнения памяти - это почти всегда очень плохой признак в вашем коде, даже если оно дает сбой задолго до того, как память фактически исчерпается, как вы испытывали из-за отсутствия постоянной памяти.

В этот момент вы должны действительно реструктурировать код.

Например, вот несколько способов борьбы с проблемой:

  1. Не храните столько данных в памяти за раз, поместите их на диск или что-то еще
  2. Разбейте его, ведите список строк / строителей строк и добавляйте к ним только определенную длину, прежде чем переходить на новую, удерживайте проблему «непрерывной памяти» в страхе
  3. Перестройте алгоритм, чтобы вообще не наращивать гигабайт данных в памяти
2 голосов
/ 12 декабря 2008

Если вы посмотрите, как реализован StringBuilder, вы увидите, что он фактически использует String для хранения данных (String имеет внутренние методы, которые позволят StringBuilder изменить на месте).

т.е. они оба используют одинаковое количество памяти. Тем не менее, поскольку StringBuilder автоматически расширяет базовый массив и при необходимости копирует (но удваивает емкость), что, скорее всего, является причиной ошибки нехватки памяти. Но, как уже указывали другие, требуется непрерывный блок памяти,

2 голосов
/ 12 декабря 2008

Если вы используете soclose до пределов своей памяти, что это даже проблема, то вам, вероятно, следует подумать о другой архитектуре или получить более мощную машину.

1 голос
/ 12 декабря 2008

Ну, на самом деле вопрос в том, зачем вам работать со строками так долго? Если вы натолкнетесь на эту проблему, скорее всего, вам следует изменить свою концепцию.

Эта проблема затрагивает даже класс System.String , поэтому вы должны скорее разделить входные данные на List и обработать данные параллельно, что должно повысить общую производительность, если написано правильно.

0 голосов
/ 23 декабря 2011

У меня был очень похожий опыт, когда я добавлял строки, но забыл добавить формат String.Format. Таким образом:

myStringBuilder.Append("1,""{0}""", someVeryLargeIntVariable)

должно было быть:

myStringBuilder.Append(String.Format("1,""{0}""", someVeryLargeIntVariable))

Обратите внимание, что это мой код vb.net, который не удался. Я повторил аналогичный тест в C # с:

myStringBuilder.Append('a', 1564544656);

против

myStringBuilder.Append(string.Format("1,\"{0}\"", 1564544656));

Но в моем случае vb.net поставил меня в тупик из-за неявных преобразований (я не смог распараллелить точную такую ​​же проблему в c #).

Надеюсь, это кому-нибудь поможет.

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

Я столкнулся с этим исключением с очень большими строками, созданными последовательно с разными строителями строк (которые не должны были вызывать проблему, поскольку они были объявлены в анонимных функциях), и в конце концов решил ее, повторно использовав один StringBuilder, объявленный вне анонимной функции.

...