Каково потребление памяти в StringBuilder? - PullRequest
6 голосов
/ 29 сентября 2008

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

Итак, прежде чем приступить к пересмотру нашего кода, я хотел бы спросить: каковы характеристики потребления памяти StringBuilder для больших строк?

Тем более, что они сравниваются со стандартным типом строки. Размер строк превышает 10 МБ, и мы, похоже, сталкиваемся с проблемами около 20 МБ.

ПРИМЕЧАНИЕ : Дело не в скорости, а в ОЗУ.

Ответы [ 5 ]

10 голосов
/ 29 сентября 2008

Каждый раз, когда StringBuilder исчерпывает пространство, он перераспределяет новый буфер в два раза больше исходного буфера, копирует старые символы и позволяет старому буферу получать GC'd. Возможно, вы просто используете достаточно (назовите это x), чтобы в 2 раза больше памяти, которую вы можете выделить. Возможно, вы захотите определить максимальную длину для ваших строк и передать ее конструктору StringBuilder, чтобы вы предварительно распределили ее, и вы не зависели от перераспределения удвоения.

6 голосов
/ 29 сентября 2008

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

Если вы можете избежать объединения, сделайте это!

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

Не использовать + = объединение когда-либо. Слишком много изменений за кулисами, которые не очевидны из моего кода в первую очередь. я советую скорее использовать String.Concat () явно с любой перегрузкой (2 строки, 3 строки, строковый массив). Это ясно покажет, что ваш код обходится без сюрпризов, пока позволяя себе контролировать эффективность.

Попробуйте оценить целевой размер StringBuilder.

Чем точнее вы можете оценить необходимый размер, менее временный Строки StringBuilder придется создать, чтобы увеличить свой внутренний буфер.

Не используйте методы Format (), если производительность является проблемой.

Слишком много накладных расходов Разбор формата, когда вы могли построить массив из частей, когда все, что вы используете, это {x} замены. Формат () хорош для удобочитаемости, но одна из вещей, чтобы пойти, когда вы выдавливая все возможные показатели вашего заявления.

3 голосов
/ 29 сентября 2008

Вас может заинтересовать структура данных веревок. Эта статья: Веревки: теория и практика объясняет их преимущества. Может быть, есть реализация для .NET.

[Обновить, чтобы ответить на комментарий] Использует ли он меньше памяти? Поиск память в статье вы найдете несколько подсказок.
В принципе, да, несмотря на структурные издержки, потому что он просто добавляет память при необходимости. StringBuilder, при исчерпании старого буфера, должен выделять гораздо больший (который может уже тратить пустую память) и отбрасывать старый (который будет собирать мусор, но в то же время может по-прежнему использовать много памяти).

Я не нашел реализацию для .NET, но есть, по крайней мере, реализация C ++ (в STI SGI: http://www.sgi.com/tech/stl/Rope.html). Возможно, вы можете использовать эту реализацию. Обратите внимание, что на странице, на которую я ссылаюсь, есть работа с памятью производительность.

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

1 голос
/ 29 сентября 2008

Strigbuilder - отличное решение проблем с памятью, вызванных объединением строк.

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

По сравнению со строкой это замечательно.

string output = "Test";
output += ", printed on " + datePrinted.ToString();
output += ", verified by " + verificationName;
output += ", number lines: " + numberLines.ToString();

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

0 голосов
/ 29 сентября 2008

Я не знаю точно образец памяти строителя строк, но обычная строка не вариант.

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

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...