Исключение StringBuilder при изменении емкости! - PullRequest
3 голосов
/ 08 июля 2011

вот моя строка кода:

StringBuilder myCompleteMessage = new StringBuilder();
myCompleteMessage.Capacity = Int32.MaxValue-1;

попробовал это также:

myCompleteMessage.Capacity = myCompleteMessage.MaxCapacity-1;

Я получаю исключение в строке 2.

Exception of type 'System.OutOfMemoryException' was thrown.

Трассировка стека:

at System.String.GetStringForStringBuilder(String value, Int32 startIndex, Int32 length, Int32 capacity)
at System.Text.StringBuilder.set_Capacity(Int32 value)
at Orca.Server.HandleClientComm(Object newClient) in C:\Users\Dan\Documents\Visual Studio 2010\Projects\msig\Orca\Server.cs:line 100
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart(Object obj)

Ответы [ 3 ]

8 голосов
/ 08 июля 2011

Если вы работаете в 32-битной системе, эта вторая строка всегда будет неудачной. Вы просите .NET выделить 4 ГБ пространства для вашего StringBuilder, что является большим объемом памяти, чем процесс, с которым приходится работать (спасибо Джоэлу за указание на то, что char занимает 2 байта, а не 1).

РЕДАКТИРОВАТЬ
Если вы посмотрите на StringBuilder с ILSpy, вы увидите этот бит кода в наборе для Capacity:

if (this.Capacity != value)
{
    int num = value - this.m_ChunkOffset;
    char[] array = new char[num];
    Array.Copy(this.m_ChunkChars, array, this.m_ChunkLength);
    this.m_ChunkChars = array;
}

Устанавливая для Capacity значение int.MaxValue - 1, вы указываете .NET попытаться выделить 4 ГБ массив символов, поэтому код не работает.

2 голосов
/ 08 июля 2011

Куча CLR ограничена 2 ГБ объектами (http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx - для 2.0, я полагаю, то же самое для 4.0), поэтому нет ничего, что могло бы выделить один непрерывный блок памяти выше этого размера.Для символов это дает вам записи о Int.MaxValue / 2.

Если вам действительно нужно управлять таким количеством текста, ознакомьтесь с альтернативными реализациями MemoryStream, которые позволяют чанкинг или массивы, которые позволяют чанкинг.Если вы хотите остаться в классах по умолчанию - рассмотрите возможность записи данных во временный файл (временный файл, созданный с помощью DeleteOnClose, может даже не записываться на диск), поэтому вы получаете лучшую производительность по сравнению со StringBuilder или MemoryStream, которые должны копировать данные при каждом увеличении емкости -http://msdn.microsoft.com/en-us/library/system.io.fileoptions.aspx).

0 голосов
/ 08 июля 2011

Свойство StringBuilder's Capacity - это количество символов, которое нужно выделить в качестве строкового буфера.С UTF-8 символ может иметь длину до 4 байтов.Даже при 2 байтах емкость Int32.MaxValue - 1 значительно превышает емкость 32-битной системы, а весит 4 ГБ только для 2-байтовых символов (UTF-8 / ASCII).Кроме того, StringBuilder по умолчанию Capacity уже установлен на Int32.MaxValue, если вы посмотрите на документацию .

Если вы зацикливаетесь для заполнения StringBuilder, возможно, вы заполняете его быстрее, чем может .NETочистите выделенную память с помощью сборки мусора, поэтому она может останавливаться на длине 2048 символов.Кроме того, внутренне ему необходим непрерывный блок памяти, с которым он также может столкнуться.

Ваш вопрос, однако, касается свойства Capacity, и вы никогда не сможете выделить столькоемкость в 32-битной системе.Я нашел интересное обсуждение по MSDN, касающееся этой конкретной проблемы, и в ходе тестирования было установлено, что фактическая емкость намного ниже, поскольку емкость Int32.MaxValue переводится в 4 ГБ памяти, которая необходима, когда все символы имеют 2-байт.

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

...