Основное отличие классов String и StringBuilder заключается в том, что при создании строки типа String выделяется ровно столько памяти, сколько необходимо для хранения инициализирующего значения. Если создается строка как объект класса StringBuilder, то выделение памяти происходит с некоторым запасом. По умолчанию, под каждую строку выделяется объем памяти, равный минимальной степени двойки, необходимой для хранения инициализирующего значения, хотя возможно задать эту величину по своему усмотрению. Например, для инициализирующего значения ”это текст” под строку типа String будет выделена память под 9 символов, а под строку типа StringBuilder – под 16 символов, из которых 9 будут использованы непосредственно для хранения данных, а еще 7 – составят запас, который можно будет использовать в случае необходимости.
Если разработчик решит добавить в строку типа StringBuilder еще один символ, например, точку, то новая строка создаваться не будет. Вместо этого будет изменен уже существующий символ, находящийся в конце используемой части строки. Аналогичные действия будут выполнены при удалении и изменении строки. Если объем добавлений превысит объем созданного запаса, произойдет создание новой строки, длина которой будет в два раза больше, чем длина предыдущей, в нее будет скопировано содержимое старой строки, и добавление продолжится.
У строки типа String такого запас нет, поэтому при попытке добавить новый символ, будет создаваться новая строка требуемой размерности.
Существование запаса памяти привело к тому, что у любого объекта класса StringBuilder есть два свойства, отвечающих за длину строки.
Свойство Length действует по аналогии со свойством Length класса String и возвращает длину хранящихся в объекте текстовых данных.
Свойство Capacity возвращает реальный объем, который занимает в памяти объект класса StringBuilder (без служебной информации, разумеется).
Следующий пример демонстрирует различие между результатами, которые возвращают эти свойства.
static void Main(string[] args)
{
string s = "Этотекст";
StringBuilder sb = new StringBuilder(s);
Console.WriteLine("Длина строки \"{0}\" = {1}", s, s.Length);
Console.WriteLine("Длина этой строки в StringBuilder = {0}", sb.Length);
Console.WriteLine("Реальная длина StringBuilder = {0}", sb.Capacity);
Console.WriteLine("Максимальная длина StringBuilder = {0}", sb.MaxCapacity);
Console.Read();
}
|
Результат работы программы ан:
Длина строки "Это текст" = 9
Длина этой строки в StringBuilder = 9
Реальная длина StringBuilder = 16
Максимальная длина StringBuilder = 2147483647
Использование StringBuilder позволяет сократить затраты памяти и времени центрального процессора при операциях, связанных с изменением строк. В то же время, на создание объектов класса StringBuilder также тратится некоторое время и память. Как следствие, в некоторых случаях операции по изменению строк оказывается «дешевле» производить непосредственно с самими строками типа String, а в некоторых – выгоднее использовать StringBuilder.
Пусть нам необходимо получить строку, состоящую из нескольких слов «текст» идущих подряд. Сделать это можно двумя способами.
Первый способ (прямое сложение строк):
string str = "";
for (int j = 0; j < count; j++)
{
str += "текст";
}
|
Второй способ (использование StringBuilder):
StringBuilder sb = new StringBuilder();
for (int j = 0; j < count; j++)
{
sb.Append("текст");
}
|
Затраты времени и памяти для каждого из случаев представлены в следующей таблице:
Число слов |
Длина строки |
String |
StringBuilder |
Время |
Затраты памяти |
Время |
Затраты памяти |
2 |
10 |
0.091 |
15 |
0.18 |
16 |
3 |
15 |
0.163 |
30 |
0.22 |
16 |
4 |
20 |
0.252 |
50 |
0.373 |
48 |
5 |
25 |
0.336 |
75 |
0.39 |
48 |
6 |
30 |
0.464 |
105 |
0.463 |
48 |
7 |
35 |
0.565 |
140 |
0.591 |
112 |
8 |
40 |
0.695 |
180 |
0.663 |
112 |
9 |
45 |
0.809 |
225 |
0.692 |
112 |
10 |
50 |
0.965 |
275 |
0.731 |
112 |
15 |
75 |
1.779 |
600 |
1.125 |
240 |
20 |
100 |
2.697 |
1050 |
1.354 |
240 |
25 |
125 |
3.811 |
1625 |
1.571 |
240 |
30 |
150 |
5.045 |
2325 |
2.144 |
496 |
35 |
175 |
6.441 |
3150 |
2.359 |
496 |
40 |
200 |
7.992 |
4100 |
2.615 |
496 |
45 |
225 |
9.59 |
5175 |
2.799 |
496 |
50 |
250 |
11.45 |
6375 |
3.03 |
496 |
Первая колонка таблицы содержит в себе число слов, из которых состоит итоговой строка. Вторая колонка показывает длину итоговой строки в символах. Третья строка таблицы показывает, за какое время было осуществлено 1000000 операций создания строки заданной длины, а четвертая – количество памяти, которое было при этом затрачено. Пятая
и шестая колонки показывают те же самые значения, но для случая использования класса StringBuilder.
В колонках «Затраты памяти» в обоих случаях стоят вычисленные эмпирически значения общего объема памяти, который был затрачен на создание строк соответствующей длины.
Как видно из этой таблицы, при числе операций сложения не больше пяти, выгоднее использовать прямое сложение строк, а если число операций сложения больше – имеет смысл использовать класс StringBuilder.
|