Сколько мусора слишком много - PullRequest
0 голосов
/ 29 июня 2018

Наше веб-приложение имеет несколько сотен пользователей и (как всегда) состоит в основном из устаревшего кода.

После нашего перехода на Azure мы смогли увидеть и измерить больше показателей, чем раньше. У нас возникают проблемы с производительностью, и я вижу, что наша сборка мусора проходит через крышу (как измерено на вкладке диагностики веб-приложения в разделе счетчиков производительности). За одну минуту мы смогли получить эти цифры:

  • 90160 GEN 0 сборки мусора
  • 76910 GEN 1 сборки мусора
  • 75110 GEN 2 сборки мусора

И это всего лишь для 18580 HTTP-запросов, поэтому в среднем мы имеем:

  • 4,85 GEN 0 сборок мусора по запросу
  • 4,13 GEN 1 сборка мусора по запросу
  • 4,04 GEN 2 сборки мусора по запросу

Эти цифры все еще растут, хотя количество запросов остается примерно одинаковым (см. График)

GC going bonkers

Мой вопрос / замечания:

  • Являются ли эти числа количеством объектов, которые очищает GC, или количеством раз, которое GC должен был быть активным?
  • При такой нагрузке, сколько GC будет считаться "нормальным", прекрасно понимая, что ни один из них не является идеальным ответом, но практически ...
  • Как это возможно, что, даже если количество запросов остается неизменным, количество сборов GC увеличивается следующим образом?

Большое спасибо заранее, John


Обновление 1: 30/06/2018 @ 8:16 UTC + 2

После обновления информации о приложениях для более тщательного наблюдения за сборкой мусора я обнаружил большой отклик в производительности. Прежде всего, это средний процент времени, проведенного в ГХ:

Average time in GC around 4 and a half percent

Это составляет в среднем около 4,5% времени (но в этот период был неактивный период в течение ночи), а в среднем - около 10% времени. Затем я подумал, чтобы представить максимальное количество времени, в течение которого приложение находилось в режиме GC, и чуть не упал со стула:

Maximum amount of time in GC around 99 percent

Это может быть неправильное изображение. Но это показывает, что нашему коду приходится много ждать GC! Нам действительно нужно это исправить.

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Эти цифры подозрительно высоки для типичного веб-приложения. Я бы сказал, что они в 10-1000 раз больше, чем обычно (75110 GEN 2 за одну минуту. Звучит скорее как микро-тест для GC :)).

Кто-то звонит GC.Collect()? Grep исходный код для этого.

Тем не менее, вам нужно выяснить, не являются ли они причиной вашей проблемы с перфорированием. Если они не вызывают это, тогда нет необходимости исправлять это. Посмотрите на время, проведенное в GC counter. Вы можете использовать PerfView, чтобы легко измерить сделанные GC паузы. Это дает вам представление о задержке паузы, с которой сталкиваются клиенты.

Являются ли эти числа количеством объектов, которые очищает GC, или количеством раз, которое GC должен был быть активным?

Это GC, а не объекты.

При такой нагрузке, сколько GC будет считаться "нормальным", прекрасно понимая, что ни один из них не является идеальным ответом, но практически ...

"Нет", конечно, не правильный ответ. Нет смысла сохранять ГХ, если это не приводит к значительному улучшению производительности. Вы тратите время на разработку впустую, если преследуете эту цель. Вы, конечно, можете взять «нормальное» количество GC.

Невозможно дать нормальный номер. Это больше о затратах времени в GC (что является накладными расходами, за которые вы должны заплатить) и времени паузы в G2, которые клиенты будут ждать в ожидании загрузки страницы.

Как это возможно, что даже если количество запросов остается неизменным, количество сборов GC увеличивается следующим образом?

Что-то ужасное сидит в вашем коде, я бы сказал :) Может быть, потоки постоянно вращаются, вызывая GC.Collect() ?! Кошмар сбылся. Grep свой код и доложить. Я расширю этот ответ, чтобы помочь вашему расследованию.

Используя PerfView или какой-либо профилировщик (я использую JetBrains), вы сможете увидеть, где GC запускаются в вашем коде.

0 голосов
/ 30 июня 2018

Звучит так, как будто вы исключили любые мошеннические GC.Collect() звонки (если только вы не ведете себя плохо в сторонней библиотеке).

Учитывая количество времени, затрачиваемого на сборку мусора, стоит проверить, увеличивается ли скорость выделения объектов в управляемой куче. Вы должны добавить счетчик производительности в Application Insights для мониторинга выделенных байтов / секунду. Не обязательно проблема, если вы не держитесь за них.

Поскольку вы говорите, что связанного с этим увеличения трафика нет, то скорее всего это проблема объектов, переживших коллекции - это может увеличить продолжительность коллекций. Это могут быть временные объекты, которые остались доступными. Вам нужно использовать профилировщик памяти, чтобы более внимательно посмотреть на это.

Стоит также сравнить с использованием памяти за те же периоды времени, чтобы помочь понять триггер для коллекций.

Профилировщик - это естественный следующий шаг для получения более точного диагноза после выявления проблемы с помощью счетчиков производительности. Особенно с такой важной проблемой, как эта, будет относительно легко определить, где что-то идет не так, иначе я просто догадываюсь. Должен также быть в состоянии подтвердить, что нет никаких принудительных (GC.Collect()) коллекций от любых библиотек.

Работает самая простая начальная точка Process Explorer - выберите процесс, щелкните правой кнопкой мыши и выберите Свойства, затем вкладку .NET Performance. Любой принудительный сборщик мусора будет отображаться под # Induced GC, так что вы можете проверить на мошеннических либах.

Если есть, вы можете использовать WinDbg для взлома GC.Collect ():

!bpmd mscorlib.dll System.GC.Collect

Если его ударили, вы можете увидеть, где он вызывается в трассировке стека:

!DumpStack
0 голосов
/ 29 июня 2018

Давайте сначала узнаем что-то для поколений:

Поколение 0 . Это самое молодое поколение и содержит недолговечные объекты. Примером недолговечного объекта является временная переменная. Сборка мусора происходит чаще всего в этом поколении.

Вновь выделенные объекты формируют объекты нового поколения и неявно являются коллекциями поколения 0, если только они не являются большими объектами, в этом случае они помещаются в кучу больших объектов в коллекции поколения 2.

Большинство объектов возвращаются для сбора мусора в поколении 0 и не сохраняются до следующего поколения.

Поколение 1 . Это поколение содержит недолговечные объекты и служит буфером между недолговечными объектами и долгоживущими объектами.

Поколение 2 . Это поколение содержит долгоживущие объекты. Примером долгоживущего объекта является объект в серверном приложении, который содержит статические данные, действующие в течение всего процесса.

Объекты, которые не возвращаются в сборщик мусора, называются выжившими и переходят в следующее поколение. Объекты, которые переживают сборку мусора поколения 0, повышаются до поколения 1; объекты, которые переживают сборку мусора поколения 1, повышаются до поколения 2; и объекты, которые переживают сборку мусора поколения 2, остаются в поколении 2.

Когда сборщик мусора обнаруживает, что выживаемость высока в поколении, он увеличивает порог выделений для этого поколения, поэтому следующая коллекция получает значительный объем восстановленной памяти. CLR постоянно уравновешивает два приоритета: не допускать, чтобы рабочий набор приложения становился слишком большим, и чтобы сбор мусора занимал слишком много времени.

Размер эфемерного сегмента варьируется в зависимости от того, является ли система 32- или 64-битной, а также от типа сборщика мусора, на котором она работает. Значения по умолчанию показаны в следующей таблице.

                                   32-bit                      64-bit

Рабочая станция GC 16 МБ 256 МБ

Сервер GC 64 МБ 4 ГБ

Серверный ГХ с> 4 логическими процессорами 32 МБ 2 ГБ

Серверный ГХ с> 8 логическими процессорами 16 МБ 1 ГБ

Эфемерный сегмент может включать объекты поколения 2. Объекты поколения 2 могут использовать несколько сегментов (столько, сколько требуется вашему процессу и памяти).

Количество освобождаемой памяти из эфемерного мусора ограничено размером эфемерного сегмента. Объем свободной памяти пропорционален пространству, которое занимали мертвые объекты.

Ссылка: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals

...