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

StackOverflow https://stackoverflow.com/questions/363680

  •  21-08-2019
  •  | 
  •  

Вопрос

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

Посмотри на Строка против StringBuilder

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

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

и еще много чего.....

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

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

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

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

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

Это было полезно?

Решение

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

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

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

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

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

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

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

Если 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, который не удался.Я повторил аналогичный тест на С#:

myStringBuilder.Append('a', 1564544656);

против.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top