В основном мы стараемся следовать приведенным выше рекомендациям.
Взгляните на Строка против StringBuilder
Но StringBuilder мог выбросить OutOfMemoryException, даже если доступно достаточно памяти. Он генерирует исключение OOM, потому что ему нужен «непрерывный блок памяти».
Некоторые ссылки для справки StringBuilder OutOfMemoryException
и многое другое .....
Кто из вас сталкивался с этой проблемой или знал, и что вы сделали для ее решения?
Что мне не хватает?
P.S: Я не знал об этом.
Я перефразировал вопрос.
*** То же самое работало и с ручной конкатенацией (я проверю это и обновлю SO). Другая вещь, которая вызвала у меня беспокойство, заключалась в том, что в системе достаточно памяти. По этой причине я поднял здесь этот вопрос, чтобы проверить, сталкивался ли кто-нибудь с этой проблемой или что-то было не так с кодом.





Создаваемая вами нижняя строка также потребует непрерывного блока памяти, поскольку она представлена как массив символов (для массивов требуется непрерывная память). Если StringBuilder выдает исключение OOM, вы не сможете построить базовый объект без него.
Если создание строки вызывает OOM, вероятно, в вашем приложении есть более серьезная проблема.
Изменить в ответ на разъяснения:
Существует небольшое подмножество случаев, когда построение строки с помощью StringBuilder завершится ошибкой при успешном объединении вручную. Ручное объединение будет использовать точную длину, необходимую для объединения двух строк, в то время как StringBuilder имеет другой алгоритм распределения памяти. Это более агрессивно и, вероятно, будет выделять больше памяти, чем фактически необходимо для строки.
Использование StringBuilder также приведет к временному удвоению требуемой памяти, поскольку строка будет присутствовать в форме System.String и StringBuilder одновременно в течение короткого времени.
Но если один способ вызывает OOM, а другой - нет, это, скорее всего, указывает на более серьезную проблему в вашей программе.
Насколько мне известно, при вызове метода StringBuilder.ToString () память для новой строки не выделяется, и данные не копируются. Созданный объект String использует ту же память, что и StringBuilder, который переходит в особое состояние «копировать при изменении». Таким образом, память будет увеличена вдвое, только если StringBuilder будет изменен после вызова ToString ().
Неправда, я проверил исходный код StringBuilder, и он выделяет новую строку и копирует байты, используя небезопасный указатель, в строковую память. Возможно, это было правдой еще в 2009 году, но точно не в 2020 году.
Если вы работаете с ограниченным объемом памяти, что даже вызывает беспокойство, вам, вероятно, следует подумать о другой архитектуре или получить более мощную машину.
Более мощная машина не поможет. OOM генерируются независимо от базового оборудования. Память - это виртуальное ограничение. Единственная аппаратная часть, которая будет иметь значение, - это 64-битная машина против 32-битной машины.
На самом деле вопрос в том, зачем вам так долго работать со строками? Если вы наткнетесь на эту проблему, скорее всего, вам следует изменить свою концепцию.
Эта проблема затрагивает даже класс System.String, поэтому вам лучше разделить ввод на Список <строка> и обрабатывать данные параллельно, что должно повысить общую производительность при правильной записи.
Если StringBuilder собирается сгенерировать исключение OutOfMemoryException в вашей конкретной ситуации, то объединение строк вручную НЕ является лучшим решением; это намного хуже. Это именно тот случай (создание очень, очень длинной строки), где предполагается использовать StringBuilder. Ручное объединение такой большой строки потребует во много раз больше памяти, чем создание строки с помощью StringBuilder.
Тем не менее, на современном компьютере, если ваша строка запуск компьютера из непрерывной памяти, ваш дизайн глубоко ошибочен. Я не могу представить, что вы могли бы сделать, чтобы создать такую большую строку.
О каком объеме памяти мы говорим? Я не говорю о свободной или общей памяти в системе, но какова длина строки, которую вы объединяете?
Исключение переполнения памяти почти всегда является очень плохим признаком вашего кода, даже если он выходит из строя задолго до того, как память фактически исчерпывается, как вы испытали из-за недоступности постоянной памяти.
На этом этапе вам действительно следует реструктурировать код.
Например, вот несколько способов борьбы с проблемой:
Если вы посмотрите, как реализован 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.
У меня была аналогичная проблема, я решил ее, указав емкость
StringBuilderзаранее, что предотвратило копирование + распределение по мере роста строки.