Каково потребление оперативной памяти StringBuilder?

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

  •  02-07-2019
  •  | 
  •  

Вопрос

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

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

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

ПРИМЕЧАНИЕ:Речь идет не о скорости, а о оперативной памяти.

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

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

По сравнению со string, это выдающийся результат.

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

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

Я не знаю о точном шаблоне памяти string builder, но общая строка - это не вариант.

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

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top