StringBuilder и емкость? - PullRequest
       35

StringBuilder и емкость?

2 голосов
/ 19 мая 2009

Я создал тестовое приложение, чтобы проверить, копирует ли StringBuilder данные в другой экземпляр и увеличивает ли он буфер, если его длина превышает текущую емкость, и проверяю в ildasm.exe, но он кажется идентичным.

Как проверить, что StringBuilder скопирует свои данные в новый экземпляр и увеличит буфер до указанного предела?

Ответы [ 6 ]

11 голосов
/ 19 мая 2009

Емкость представляет непрерывную память, выделенную для StringBuilder. Емкость может быть> = длина строки. Когда к StringBuilder добавляется больше данных, чем емкости, StringBuilder автоматически увеличивает емкость. Поскольку емкость превышена (то есть непрерывная память заполнена и больше нет доступной буферной комнаты), выделяется большая область буфера и данные копируются из исходной памяти в эту новую область.

Копирует данные не в новый «экземпляр», а в новую «ячейку памяти». Экземпляр остается прежним, но указывает на новую ячейку памяти.

Редактировать К вашему сведению: емкость StringBuilder по умолчанию, если она не указана при создании, составляет 16

Если вы хотите увидеть места в памяти для StringBuilder, вы можете отладить свои приложения и проверить память, используя Отладка> Windows> Память. На самом деле вы можете видеть адрес каждого байта, хранящегося в вашем StringBuilder, когда запускается команда добавления stmt.

Если вам нужно получить данные о местоположении программно , эта ссылка может помочь.

5 голосов
/ 19 мая 2009

Если вы хотите проверить, как реализован StringBuilder, просто запустите Reflector и посмотрите на него. Реализация для StringBuilder.Append(string) выглядит следующим образом

public StringBuilder Append(string value)
{
   if (value != null)
   {
      string stringValue = this.m_StringValue;
      IntPtr currentThread = Thread.InternalGetCurrentThread();
      if (this.m_currentThread != currentThread)
      {
         stringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
      }
      int length = stringValue.Length;
      int requiredLength = length + value.Length;
      if (this.NeedsAllocation(stringValue, requiredLength))
      {
         string newString = this.GetNewString(stringValue, requiredLength);
         newString.AppendInPlace(value, length);
         this.ReplaceString(currentThread, newString);
      }
      else
      {
         stringValue.AppendInPlace(value, length);
         this.ReplaceString(currentThread, stringValue);
      }
   }
   return this;
}

Посмотрите на раздел с NeedsAllocation, GetNewString и т. Д., Чтобы найти то, что вы ищете.

5 голосов
/ 19 мая 2009

Не то чтобы мы действительно проверяли, что StringBuilder работает, потому что он работает, но для вашего собственного удовольствия вы всегда можете написать модульный тест.

StringBuilder sb = new StringBuilder(10);
Console.WriteLine("Capacity = " + sb.Capacity + " Length = " + sb.Length 
      + " MaxCapacity = " + sb.MaxCapacity);
sb.Append("1234567890");
sb.Append("1234567890");
sb.Append("1234567890");
Console.WriteLine("Capacity = " + sb.Capacity + " Length = " + sb.Length 
      + " MaxCapacity = " + sb.MaxCapacity);
Assert.AreEqual("123456789012345678901234567890"
      , sb.ToString()); // NUnit assert.

Неудивительно, что оно проходит, и выдается следующий вывод.

    Capacity = 10 Length = 0 MaxCapacity = 2147483647
    Capacity = 40 Length = 30 MaxCapacity = 2147483647
2 голосов
/ 19 мая 2009

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

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

0 голосов
/ 14 декабря 2012
 class Program
    {
        static void Main()
        {
            StringBuilder sb = new StringBuilder();
            Console.WriteLine(sb.Capacity); //16

            for (int i = 0; i < 50; i++) 
                sb.Append(i + ",");

            Console.WriteLine(sb.Capacity); //256

            sb = new StringBuilder();
            Console.WriteLine(sb.Capacity); //16
        }
    }
0 голосов
/ 19 мая 2009

Вы можете использовать Reflector, чтобы увидеть, как работает StringBuilder.

См метод

StringBuilder Append(string value)

Для .Net 3.5 логика такова: если длины буфера недостаточно для новой строки, создайте новый буфер с длиной, равной Max (oldSize * 2, requiredSize).

Другими словами, StringBuffer пытается удвоить буфер и, если этого недостаточно, делает размер буфера достаточным для новой строки.

Ссылка на старый буфер удаляется, а старый буфер восстанавливается при следующей сборке мусора.

...