Friday, November 1, 2013

StringBuilder vs String

StringBuilder  это класс, который предоставляет подобный строке объект, значение которого является изменяемой последовательностью знаков. Значение является изменяемым, поскольку его можно модифицировать после создания путем добавления, удаления, вставки или замены символов. 
Рассуждая над статьей про расхваливаемый автором StringBuilder на habrahabr.ru , позволю изложить некоторые собственные исследования. Проведем краткое описание класса String и StringBuilder.
String 
Тип string представляет собой последовательность из нуля или более символов в кодировке Unicode. Тип string — это псевдоним для типа String платформы .NET Framework.
 Алгоритм распределения памяти 20+(n/2)x4 байт, где n — количество символов в строке или, что одно и то же, — её длина. Источник: http://csharpindepth.com/Articles/General/Strings.aspx Джон Скит.
Класс string для выделения памяти использует функции FastAllocateString и FillStringChecked для заполнения. Последние являются native функциями для выделения памяти для строк. Источник: http://geekswithblogs.net/johnsPerfBlog/archive/2005/05/27/40777.aspx
StringBuilder
StringBuilder  размер по умолчанию, равен 16 байт. При большом объеме данных StringBuilder использует LOH (Large Object Heap), что существенно увеличивает быстродействие, так как LOH не дефрагменируемая и доступ к ней осуществляется очень быстро. Сборка мусора проходит реже, поскольку Garbage Collector работает по определенному принципу для массивных объектов. Источник MSDN. В .Net 2.0 реализовано хранение данных через внутренний буфер (данные лежат в стеке, поэтому доступ к ним осуществляется быстрее). В .Net 4.0 и выше StringBuilder реализован в виде связного списка. То есть работает еще быстрее благодаря тому, что оперирует для доступа к данным через указатели. 
Подробнее можно почитать здесь: habrahabr.ru
Сравнение StringBuilder vs String
StringBuilder
Плюсы:
  • Если размер Capacity в StringBuilder будет очень большой, он будет перемещен в Large Object Heap,  в котором нет дефрагментации памяти при сборке мусора и последняя будет происходить, скорее всего, непрерывно, так как механизм выделения памяти остается прежним. (Минус — что данных будет у два раза меньше, потому что Capacity увеличивается в два раза, когда требуется место для хранения новых данных).
  • StringBuilder в .NET 2.0 был оптимизирован на быстроту работы метода ToString(), а в .NET 4.0 — на быстроту метода Append(). Новая реализация метода Append() работает почти в 2 раза быстрее, в то время как методы Insert() и ToString() работают медленнее. 
Минусы:
Пример использования StringBuilder
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 100000; i++)
{
    builder.Append("!");
}
string x = builder.ToString();

Приведенный выше код имеет один из основных недостатков — это постоянное увеличение Capacity. (Как вариант использовать сразу EnsureCapacity). В .Net 2.0 это имело свои расходы, так как нужно было создавать новый внутренний буфер и скопировать туда значение, например, тем же Array.Copy, хотя на уровне mscorlib, вероятно, используется что-то вроде AllocatedMemory. В .Net 4.0 данные в StringBuilder хранятся в виде связного списка. Поэтому при перераспределении памяти,по сути, будут просто скопированы указатели.
Огромным недостатком StringBuilder есть то, что для маленьких записей использование функций Append, Insert только усложнит код чтение кода и не даст никакого прироста производительности.
String
Плюсы:
для строк вида


string s = "Hi" + " all";

не будет вызвано string.Concat, как, казалось,  должно было быть по определению. Компилятор знает, что все составные части строки s являются константами времени компиляции, и поэтому все они будут конкатенированы ещё в момент компиляции программы, и в скомпилированном коде будет храниться строка s со значением "Hi all". Источник: Джеффри Рихтер "CLR via C#".
Удобство использования, конкатенация, удаление. Для StringBuilder, например, чтобы написать код в таком виде:

StringBuilder builder = new StringBuilder();
builder += "a";
builder = "b" + "c";
нужно писать extension methods.
Минусы: недостатки использования конкатенации строк для больших данных.

string x = "";
for (int i = 0; i < 100000; i++)
{
    x += "!";
}
Получаем по алгоритму 20+(n/2)x4 каждый раз создание новой строки больше предыдущей. То есть, в куче будет создано много мелких объектов x на каждую строку, так как string это immutable object. Если объектов немного, то сборка мусора и перераспределение памяти будет частая, так как объекты занимают 0-ю очередь в Garbage CollectorСтрока вида x += "!" вызывает функцию string.Concat.



No comments:

Post a Comment