Вопрос по memory, stringbuilder, garbage-collection, c# – интересное исключение OutOfMemory с StringBuilder

11

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

Что в основном происходит здесь, я создаю строку, используяXmlWriter сStringBuilder на основании некоторых данных. Затем я вызываю метод из внешней библиотеки, который преобразует эту строку XML в другую строку. После этого преобразованная строка сохраняется в базе данных. Все это повторяется в цикле около 100 раз для разных данных.

Строки сами по себе не слишком велики (менее 500 Кбайт каждая), и память процесса не увеличивается во время этого цикла. Но все же, иногда я получаюOutOfMemeoryExcpetion вStringBuilder.Append, Интересно, что это исключение не приводит к падению. Я могу поймать это исключение и продолжить цикл.

Что здесь происходит? Зачем мне получатьOutOfMemoryException хотя в системе все еще достаточно свободной памяти? Это какая-то проблема с кучей GC?

Учитывая, что я могуt обойти преобразование всех этих строк, что я могу сделать, чтобы сделать эту работу надежно? Должен ли я форсировать сбор GC? Следует положитьThread.Sleep в петлю? Должен ли я прекратить использованиеStringBuilder? Следует просто повторить попытку при столкновении с?OutOfMemoryException

Ваш Ответ

3   ответа
14

но нет смежного сегмента, который может обрабатывать размер вашего строителя строк. Вы должны знать, что каждый раз, когда буфер строителя строк слишком короткий, его размер удваивается. Если вы можете определить (в ctor) размер вашего компоновщика, он 'лучше. Вы МОЖЕТЕ позвонитьGC.Collect() когда вы закончите с большой коллекцией объектов.

На самом деле, когда у вас есть OutOfMemory, он, как правило, показывает плохой дизайн, вы можете использовать жесткий диск (временные файлы) вместо памяти, вы не должныВыделять память снова и снова (попробуйте повторно использовать объекты / буферы / ...).

Я настоятельно советую вам прочитать этот пост “Недостаточно памяти" Не относится к физической памяти от Эрика Липперта.

+1 за статью Paul Draper
SB имеет буфер, если вы повторно используете SB, вы можете повторно использовать буфер. Если вы создаете новый SB каждый раз, вы создаете новый буфер каждый раз, а старые буферы находятся в мусоре. Даже если размер многократно используемого строителя строк уменьшен, мусора будет намного меньше, поскольку есть только буферы от этого сборщика, а не все буферы от всех строителей строк предыдущих операций. Guillaume
Ну, это может перераспределить, но если в мусоре нет другого SB, это будет намного более эффективно. Guillaume
Если я буду использовать один и тот же StringBuilder снова и снова, буду ли я использовать один и тот же сегмент памяти (кроме случаев, когда SB нужно увеличить себя)? Wouldn»Разве это не решает все мои проблемы (скорее всего)? bitbonk
3

ных.

После или до использования просто сбросьте размер StringBuilder на 0 и начните добавлять. Это уменьшит количество выделений и, возможно, сделает ситуацию OutOfMemory очень редкой.

Чтобы проиллюстрировать мою точку зрения:

void MainProgram()
{
    StringBuilder builder = new StringBuilder(2 * 1024); //2 Kb

    PerformOperation(builder);
    PerformOperation(builder);
    PerformOperation(builder);
    PerformOperation(builder);
}

void PerformOperation(StringBuilder builder)
{
    builder.Length = 0;

    //
    // do the work here builder.Append(...);
    //
}
3

Куча больших объектов (LOH) фрагментация.

Повторное использование объектов StringBuilder не является прямым решением, вам нужно получить контроль над базовыми буферами.

Если возможно, рассчитайте или оцените размер заранее и предварительно выделите.

И это может помочь, если вы вокругвверх ассигнования, пустьскажем, кратно 20 КБ или около того. Это может улучшить повторное использование.

Почему повторное использование объектов StringBuilder не является прямым решением? Вы просто подразумеваете, что повторное использование + предварительное распределение (размера, который подходит всем будущим строкам) будет решением? bitbonk
bitbonk, да, что-то в этом роде. Худший шаблон для LOH - это выделение блоков с увеличивающимся размером и / или чередование коротких и долгоживущих блоков. Henk Holterman

Похожие вопросы