StringBuilder для конкатенации строк выдает исключение OutOfMemoryException

В основном мы стараемся следовать приведенным выше рекомендациям.

Взгляните на Строка против StringBuilder

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

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

и многое другое .....

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

Что мне не хватает?

P.S: Я не знал об этом.

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

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

У меня была аналогичная проблема, я решил ее, указав емкость StringBuilder заранее, что предотвратило копирование + распределение по мере роста строки.

Menahem 16.08.2011 17:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
16
1
21 096
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

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

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

Изменить в ответ на разъяснения:

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

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

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

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

Roman Boiko 28.11.2009 00:49

Неправда, я проверил исходный код StringBuilder, и он выделяет новую строку и копирует байты, используя небезопасный указатель, в строковую память. Возможно, это было правдой еще в 2009 году, но точно не в 2020 году.

zvolkov 30.10.2020 00:39

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

Более мощная машина не поможет. OOM генерируются независимо от базового оборудования. Память - это виртуальное ограничение. Единственная аппаратная часть, которая будет иметь значение, - это 64-битная машина против 32-битной машины.

JaredPar 12.12.2008 21:31

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

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

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

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

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

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

На этом этапе вам действительно следует реструктурировать код.

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

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

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

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

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

У меня был очень похожий опыт, когда я добавлял строки, но забыл добавить 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 доставил мне проблему b / c неявных преобразований (я не мог распараллелить ту же проблему точный в C#).

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

Использование String.Format с StringBuilder лишает преимущества использования StringBuilder.

M.Babcock 23.12.2011 02:04

Другие вопросы по теме