Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье описываются проблемы, связанные с сбором мусора и использованием памяти. В нем рассматриваются проблемы, относящиеся к управляемой куче, и объясняется, как свести к минимуму влияние сборки мусора на приложения. Каждая проблема содержит ссылки на процедуры, которые можно использовать для изучения проблем.
Средства анализа производительности
В следующих разделах описываются средства, доступные для изучения проблем использования памяти и сборки мусора. Описанные далее в этой статье процедуры относятся к этим средствам.
Счетчики производительности памяти
Счетчики производительности можно использовать для сбора данных о производительности. Инструкции см. в разделе "Профилирование среды выполнения". Категория счетчиков производительности памяти .NET CLR, как описано в счетчиках производительности в .NET, предоставляет информацию о сборщике мусора.
Отладка с помощью SOS
Вы можете использовать отладчик Windows (WinDbg) для проверки объектов в управляемой куче.
Чтобы установить WinDbg, установите средства отладки для Windows на странице "Скачать средства отладки для Windows ".
События трассировки мусора
Трассировка событий для Windows (ETW) — это система трассировки, которая дополняет профилирование и отладку, предоставляемую .NET. Начиная с .NET Framework 4, события ETW для сборки мусора собирают полезные сведения для анализа управляемой кучи со статистической точки зрения. Например, событие, GCStart_V1
которое возникает при сборке мусора, предоставляет следующие сведения:
- Какое поколение объектов собирается.
- Что активировало сборку мусора.
- Тип сборки мусора (параллельная или не одновременная).
Ведение журнала событий ETW эффективно и не будет скрывать проблемы с производительностью, связанные со сборкой мусора. Процесс может предоставлять собственные события в сочетании с событиями ETW. При регистрации события приложения и события сборки мусора можно сопоставить, чтобы определить, как и когда возникают проблемы с кучей. Например, серверное приложение может предоставлять события в начале и конце клиентского запроса.
API профилирования
Интерфейсы профилирования среды CLR предоставляют подробные сведения об объектах, затронутых во время сборки мусора. Профилировщик может получать уведомления о начале и завершении сборки мусора. Он может предоставлять отчеты об объектах в управляемой куче с идентификацией объектов в каждой генерации. Дополнительные сведения см. в разделе "Обзор профилирования".
Профилировщики могут предоставлять исчерпывающую информацию. Однако сложные профилировщики могут потенциально изменить поведение приложения.
Мониторинг ресурсов домена приложения
Начиная с .NET Framework 4, мониторинг ресурсов домена приложения (ARM) позволяет узлам отслеживать использование ЦП и памяти по домену приложения. Дополнительные сведения см. в разделе "Мониторинг ресурсов домена приложения".
Устранение неполадок с производительностью
Первым шагом является определение того, является ли проблема фактически сборкой мусора. Если вы определите, что это так, выберите из следующего списка, чтобы устранить проблему.
- Возникает исключение из-за нехватки памяти
- Процесс использует слишком много памяти
- Сборщик мусора не освобождает объекты достаточно быстро
- Управляемая куча слишком фрагментирована
- Задержки при сборке мусора слишком долгие
- Поколение 0 слишком большое
- Загрузка ЦП во время сборки мусора слишком высока
Проблема: выдается исключение из-за нехватки памяти
Существует два законных случая для создания управляемого:OutOfMemoryException
Не хватает виртуальной памяти.
Сборщик мусора выделяет память из операционной системы в сегментах заранее установленного размера. Если для выделения требуется дополнительный сегмент, но в пространстве виртуальной памяти процесса нет смежного свободного блока, выделение для управляемой кучи будет неудачным.
Недостаточно физической памяти для выделения.
Проверки производительности |
---|
Определите, обрабатывается ли исключение недостатка памяти. Определите, сколько виртуальной памяти можно резервировать. Определите, достаточно ли физической памяти. |
Если вы определите, что исключение не является законным, обратитесь в службу поддержки клиентов Майкрософт со следующими сведениями:
- Стек с исключением нехватки памяти в управляемом коде.
- Полный дамп памяти.
- Данные, свидетельствующие о том, что это не является допустимым исключением из-за нехватки памяти, включая данные, подтверждающие, что виртуальная или физическая память не представляет собой проблему.
Проблема. Процесс использует слишком много памяти
Распространенное предположение заключается в том, что отображение использования памяти на вкладке "Производительность " диспетчера задач Windows может указывать, когда используется слишком много памяти. Однако это отображение относится к рабочему набору; Он не предоставляет сведения об использовании виртуальной памяти.
Если определить, что проблема вызвана управляемой кучей, необходимо измерить управляемую кучу с течением времени, чтобы определить все шаблоны.
Если определить, что проблема не вызвана управляемой кучей, необходимо использовать собственную отладку.
Проблема: сборщик мусора не освобождает объекты достаточно быстро
Когда кажется, что объекты не собираются для утилизации так, как ожидалось, необходимо определить, есть ли на эти объекты сильные ссылки.
Вы также можете столкнуться с этой проблемой, если для поколения, содержащего мертвый объект, не была проведена сборка мусора, что означает, что финализатор для мертвого объекта не был запущен. Например, это возможно, если вы используете приложение с однопоточной моделью (STA), и поток, который обслуживает очередь завершителей, не может обратиться к нему.
Проверки производительности |
---|
Проверьте ссылки на объекты. Проверьте, был ли запущен финализатор. Определите, есть ли объекты, ожидающие завершения. |
Проблема: управляемая куча слишком фрагментирована
Уровень фрагментации вычисляется как отношение свободного пространства к общему объему выделенной памяти для поколения. Для поколения 2 допустимый уровень фрагментации составляет не более 20%. Поскольку поколение 2 может становиться очень большим, уровень фрагментации более важен, чем абсолютное значение.
Наличие большого количества свободного места в поколении 0 не является проблемой, так как это поколение, в котором выделяются новые объекты.
Фрагментация всегда происходит в куче больших объектов, так как она не сжимается. Свободные объекты, расположенные рядом, естественно объединяются в единое пространство для удовлетворения запросов на выделение больших объектов.
Фрагментация может стать проблемой в поколении 1 и поколении 2. Если эти поколения имеют большое свободное пространство после сборки мусора, использование объекта приложения может потребовать изменения, и следует рассмотреть возможность повторной оценки времени существования долгосрочных объектов.
Чрезмерное закрепление объектов может увеличить фрагментацию. Если фрагментация высока, слишком много объектов может быть закреплено.
Если фрагментация виртуальной памяти не позволяет сборщику мусора добавлять сегменты, причины могут быть одним из следующих:
Частая загрузка и выгрузка множества небольших узлов.
При взаимодействии с неуправляемыми кодами слишком много ссылок на COM-объекты.
Создание больших временных объектов приводит к тому, что куча крупных объектов часто выделяет и освобождает сегменты памяти.
При размещении среды CLR приложение может запросить, чтобы сборщик мусора сохранил свои сегменты. Это уменьшает частоту выделения сегментов. Это достигается с помощью флага STARTUP_HOARD_GC_VM в перечислении STARTUP_FLAGS.
Проверки производительности |
---|
Установите объем свободного пространства в управляемой куче. Определите количество закрепленных объектов. |
Если вы считаете, что нет законной причины фрагментации, обратитесь в службу поддержки Майкрософт.
Проблема: паузы сборки мусора слишком длительны
Сборка мусора работает в мягком режиме реального времени, поэтому приложение должно иметь возможность терпеть некоторые паузы. Критерий мягкого реального времени заключается в том, что 95% операций должны завершиться вовремя.
В сборке мусора с параллельной обработкой управляемые потоки получают возможность выполнения во время процесса сбора мусора, что означает, что приостановки очень небольшие.
Эфемерные сборки мусора (поколения 0 и 1) продолжаются всего несколько миллисекунд, поэтому снижение задержек обычно нецелесообразно. Однако можно уменьшить паузы в коллекциях поколения 2, если приложение изменит шаблон запросов на выделение памяти.
Другой, более точный метод заключается в использовании событий ETW сборки мусора. Вы можете определить время сбора, суммируя разницу временных меток для последовательности событий. Вся последовательность сбора включает приостановку исполняющего механизма, сам сбор мусора и возобновление исполняющего механизма.
Вы можете использовать уведомления о сборке мусора , чтобы определить, должен ли сервер иметь коллекцию поколения 2 и может ли перенаправление запросов на другой сервер облегчить любые проблемы с приостановками.
Проверки производительности |
---|
Определите продолжительность времени в сборке мусора. Определите причину сборки мусора. |
Проблема: поколение 0 слишком большое
Поколение 0, скорее всего, будет иметь больше объектов в 64-разрядной системе, особенно при использовании сборки мусора сервера вместо сборки мусора рабочей станции. Это связано с тем, что пороговое значение для активации сборки мусора поколения 0 выше в этих средах, и коллекции поколения 0 могут значительно увеличиться. Производительность улучшается, когда приложение выделяет больше памяти перед активацией сборки мусора.
Проблема. Загрузка ЦП во время сборки мусора слишком высока
Загрузка ЦП будет высокой во время сборки мусора. Если значительное время процесса тратится на сборку мусора, количество сборок слишком велико или сборка длится слишком долго. Увеличение скорости распределения объектов в управляемой куче приводит к увеличению частоты сборки мусора. Уменьшение скорости распределения снижает частоту сборок мусора.
Вы можете отслеживать показатели распределения с помощью счетчика Allocated Bytes/second
производительности. Дополнительные сведения см. в разделе "Счетчики производительности" в .NET.
Длительность коллекции в первую очередь зависит от числа объектов, которые выживают после распределения. Сборщик мусора должен обработать большой объем памяти, если многие объекты остаются для сбора. Работа по обработке выживших требует много времени. Чтобы определить, сколько объектов было обработано во время сборки мусора, установите точку останова в отладчике в конце сборки мусора для конкретной генерации.
Проверки производительности |
---|
Определите, вызвана ли высокая загрузка ЦП сборкой мусора. Установите точку останова в конце сборки мусора. |
Рекомендации по устранению неполадок
В этом разделе описаны рекомендации, которые следует учитывать при начале расследования.
Сборка мусора рабочей станции или сервера
Определите, используете ли вы правильный тип сборки мусора. Если приложение использует несколько потоков и экземпляров объектов, используйте сборку мусора сервера вместо сборки мусора рабочей станции. Серверная сборка мусора работает с несколькими потоками, в то время как сборка мусора рабочей станции требует, чтобы несколько экземпляров приложения запускали свои собственные потоки сборки мусора и соревновались за время ЦП.
Приложение, которое имеет низкую нагрузку и выполняет задачи редко в фоновом режиме, например служба, может использовать сборку мусора рабочей станции с отключенной параллельной сборкой мусора.
Когда следует измерять размер управляемой кучи
Если вы не используете профилировщик, необходимо установить согласованный шаблон измерения для эффективной диагностики проблем с производительностью. Рассмотрим следующие моменты, чтобы установить расписание:
- Если вы измеряете после сборки мусора поколения 2, вся управляемая куча будет свободна от мусора (мертвых объектов).
- Если вы измеряете сразу после сборки мусора поколения 0, объекты в поколениях 1 и 2 еще не будут собраны.
- Если вы измеряете непосредственно перед сборкой мусора, вы сможете измерить как можно большее количество выделенной памяти до начала сборки мусора.
- Измерение во время сборки мусора проблематично, так как структуры данных сборщика мусора не находятся в допустимом состоянии для обхода и могут не дать полные результаты. Это сделано намеренно.
- При использовании сборки мусора рабочей станции с одновременной сборкой мусора освобожденные объекты не компактизируются, поэтому размер кучи может быть одинаковым или больше (фрагментация может сделать его визуально больше).
- Параллельная сборка мусора поколения 2 задерживается, когда нагрузка физической памяти слишком высока.
В следующей процедуре описывается, как задать точку останова, чтобы можно было измерить управляемую кучу.
Установить точку останова в конце сборки мусора
В WinDbg с загруженным расширением отладчика SOS введите следующую команду:
bp mscorwks!WKS::GCHeap::RestartEE "j (dwo(mscorwks!WKS::GCHeap::GcCondemnedGeneration)==2) 'kb';'g'"
Установите
GcCondemnedGeneration
на требуемое поколение. Для этой команды требуются закрытые символы.Эта команда вызывает разрыв, если
RestartEE
выполняется после освобождения объектов поколения 2 для сборки мусора.В серверной сборке мусора вызывается только один поток
RestartEE
, поэтому точка останова произойдет только один раз во время сборки мусора поколения 2.
Процедуры проверки производительности
В этом разделе описаны следующие процедуры, чтобы изолировать причину проблемы с производительностью:
- Определите, вызвана ли проблема сборкой мусора.
- Определите, обрабатывается ли исключение недостатка памяти.
- Определите, сколько виртуальной памяти можно резервировать.
- Определите, достаточно ли физической памяти.
- Определите, сколько памяти выделяет управляемая куча.
- Определите, сколько памяти резервирует управляемая куча.
- Определение больших объектов в поколении 2.
- Определите ссылки на объекты.
- Проверьте, был ли запущен финализатор.
- Определите, есть ли объекты, ожидающие завершения.
- Установите объем свободного пространства в управляемой куче.
- Определите количество закрепленных объектов.
- Определите продолжительность времени в сборке мусора.
- Определите, что активировало сборку мусора.
- Определите, вызвана ли высокая загрузка ЦП сборкой мусора.
Чтобы определить, вызвана ли проблема сборкой мусора
Проверьте следующие два счетчика производительности памяти:
% время в GC. Отображает процент истекшего времени, затраченного на выполнение сборки мусора после последнего цикла сборки мусора. Используйте этот счетчик, чтобы определить, тратится ли сборщик мусора слишком много времени, чтобы сделать управляемое пространство кучи доступным. Если время, затраченное на сборку мусора, относительно низко, это может указывать на проблему ресурсов за пределами управляемой кучи. Этот счетчик может быть не точным, если используется параллельная или фоновая сборка мусора.
# Всего зарезервированных байтов. Отображает объем виртуальной памяти, выделенной сборщиком мусора. Используйте этот счетчик, чтобы определить, является ли память, используемая сборщиком мусора, чрезмерной долей памяти, которую использует ваше приложение.
Большинство счетчиков производительности памяти обновляются в конце каждой сборки мусора. Поэтому они могут не отражать текущие условия, о которых требуется информация.
Чтобы определить, правильно ли управляется исключение, связанное с нехваткой памяти.
В отладчике WinDbg или Visual Studio с загруженным расширением отладчика SOS, введите команду вывода исключения (
pe
) :!pe
Если исключение управляемо, OutOfMemoryException отображается как тип исключения, как показано в следующем примере.
Exception object: 39594518 Exception type: System.OutOfMemoryException Message: <none> InnerException: <none> StackTrace (generated):
Если выходные данные не указывают исключение, необходимо определить, из какого потока произошло исключение нехватки памяти. Введите следующую команду в отладчике, чтобы отобразить все потоки со своими стеками вызовов:
~\*kb
Поток, содержащий стек с вызовами исключений, обозначается аргументом
RaiseTheException
. Это управляемый объект исключения.28adfb44 7923918f 5b61f2b4 00000000 5b61f2b4 mscorwks!RaiseTheException+0xa0
Для выгрузки вложенных исключений можно использовать эти команды.
!pe -nested
Если вы не найдете никаких исключений, исключение вне памяти возникло из неуправляемого кода.
Определение объема виртуальной памяти, который можно зарезервировать
В WinDbg с загруженным расширением отладчика SOS введите следующую команду, чтобы получить самый большой бесплатный регион:
!address -summary
Самый большой свободный регион отображается, как показано в следующих выходных данных.
Largest free region: Base 54000000 - Size 0003A980
В этом примере размер крупнейшего свободного региона составляет примерно 24000 КБ (3A980 в шестнадцатеричном). Этот регион гораздо меньше, чем то, что требуется сборщику мусора для сегмента.
–или–
Используйте команду
vmstat
:!vmstat
Самый большой свободный регион — это наибольшее значение в столбце MAXIMUM, как показано в следующих выходных данных.
TYPE MINIMUM MAXIMUM AVERAGE BLK COUNT TOTAL ~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~~~ ~~~~ Free: Small 8K 64K 46K 36 1,671K Medium 80K 864K 349K 3 1,047K Large 1,384K 1,278,848K 151,834K 12 1,822,015K Summary 8K 1,278,848K 35,779K 51 1,824,735K
Определение наличия достаточной физической памяти
Запустите диспетчер задач Windows.
На вкладке
Performance
обратите внимание на зафиксированное значение. (В Windows 7 посмотрите наCommit (KB)
вSystem group
.)Если
Total
близко кLimit
, ваша система испытывает нехватку физической памяти.
Для определения объема памяти, зарезервированной управляемой кучей
# Total committed bytes
Используйте счётчик производительности памяти, чтобы получить количество байтов, которые управляемая куча выделяет. Сборщик мусора закрепляет блоки в сегменте по мере необходимости, а не все одновременно.Замечание
Не используйте счетчик
# Bytes in all Heaps
производительности, так как он не отражает фактическое использование памяти управляемой кучей. Размер поколения включается в это значение и на самом деле является его пороговым размером, то есть размером, вызывающим сборку мусора, если поколение заполнено объектами. Поэтому обычно это значение равно нулю.
Определение объема памяти, резервируемой управляемой кучей
# Total reserved bytes
Используйте счетчик производительности памяти.Сборщик мусора резервирует память в сегментах, и вы можете определить, где начинается сегмент с помощью
eeheap
команды.Это важно
Хотя можно определить объем памяти, который сборщик мусора выделяет для каждого сегмента, размер сегмента зависит от реализации и в любой момент может изменяться, в том числе в периодических обновлениях. Приложение не должно делать никаких допущений относительно размера определенного сегмента, полагаться на него или пытаться настроить объем памяти, доступный для выделения сегментов.
В отладчике WinDbg или Visual Studio с загруженным расширением отладчика SOS введите следующую команду:
!eeheap -gc
Результат выглядит следующим образом.
Number of GC Heaps: 2 ------------------------------ Heap 0 (002db550) generation 0 starts at 0x02abe29c generation 1 starts at 0x02abdd08 generation 2 starts at 0x02ab0038 ephemeral segment allocation context: none segment begin allocated size 02ab0000 02ab0038 02aceff4 0x0001efbc(126908) Large object heap starts at 0x0aab0038 segment begin allocated size 0aab0000 0aab0038 0aab2278 0x00002240(8768) Heap Size 0x211fc(135676) ------------------------------ Heap 1 (002dc958) generation 0 starts at 0x06ab1bd8 generation 1 starts at 0x06ab1bcc generation 2 starts at 0x06ab0038 ephemeral segment allocation context: none segment begin allocated size 06ab0000 06ab0038 06ab3be4 0x00003bac(15276) Large object heap starts at 0x0cab0038 segment begin allocated size 0cab0000 0cab0038 0cab0048 0x00000010(16) Heap Size 0x3bbc(15292) ------------------------------ GC Heap Size 0x24db8(150968)
Адреса, указанные "сегментом", являются начальными адресами сегментов.
Определение больших объектов в поколении 2
В отладчике WinDbg или Visual Studio с загруженным расширением отладчика SOS введите следующую команду:
!dumpheap –stat
Если управляемая куча большая,
dumpheap
может потребовать некоторое время.Вы можете начать анализ из последних нескольких строк выходных данных, так как они перечисляют объекты, использующие наибольшее пространство. Рассмотрим пример.
2c6108d4 173712 14591808 DevExpress.XtraGrid.Views.Grid.ViewInfo.GridCellInfo 00155f80 533 15216804 Free 7a747c78 791070 15821400 System.Collections.Specialized.ListDictionary+DictionaryNode 7a747bac 700930 19626040 System.Collections.Specialized.ListDictionary 2c64e36c 78644 20762016 DevExpress.XtraEditors.ViewInfo.TextEditViewInfo 79124228 121143 29064120 System.Object[] 035f0ee4 81626 35588936 Toolkit.TlkOrder 00fcae40 6193 44911636 WaveBasedStrategy.Tick_Snap[] 791242ec 40182 90664128 System.Collections.Hashtable+bucket[] 790fa3e0 3154024 137881448 System.String Total 8454945 objects
Последний объект, указанный в списке, является строкой и занимает больше всего места. Вы можете изучить приложение, чтобы узнать, как можно оптимизировать объекты строки. Чтобы просмотреть строки в диапазоне от 150 до 200 байт, введите следующее:
!dumpheap -type System.String -min 150 -max 200
Ниже приведен пример результатов.
Address MT Size Gen 1875d2c0 790fa3e0 152 2 System.String HighlightNullStyle_Blotter_PendingOrder-11_Blotter_PendingOrder-11 …
Использование целого числа вместо строки для идентификатора может быть более эффективным. Если одна и та же строка повторяется тысячами раз, рассмотрите возможность интернинга строк. Дополнительные сведения о интернинге строк см. в справочном String.Intern разделе для метода.
Определение ссылок на объекты
В WinDbg с загруженным расширением отладчика SOS введите следующую команду, чтобы получить список ссылок на объекты:
!gcroot
–или–
Чтобы определить ссылки для определенного объекта, добавьте адрес:
!gcroot 1c37b2ac
Корни, найденные на стеках, могут быть ложноположительными результатами. Чтобы получить дополнительные сведения, используйте команду
!help gcroot
.ebx:Root:19011c5c(System.Windows.Forms.Application+ThreadContext)-> 19010b78(DemoApp.FormDemoApp)-> 19011158(System.Windows.Forms.PropertyStore)-> … [omitted] 1c3745ec(System.Data.DataTable)-> 1c3747a8(System.Data.DataColumnCollection)-> 1c3747f8(System.Collections.Hashtable)-> 1c376590(System.Collections.Hashtable+bucket[])-> 1c376c98(System.Data.DataColumn)-> 1c37b270(System.Data.Common.DoubleStorage)-> 1c37b2ac(System.Double[]) Scan Thread 0 OSTHread 99c Scan Thread 6 OSTHread 484
Команда
gcroot
может занять много времени на выполнение. Любой объект, который не был возвращен сборкой мусора, является динамическим объектом. Это означает, что какой-то корневой элемент прямо или косвенно удерживает объект, поэтомуgcroot
должен возвращать информацию о пути к объекту. Необходимо проверить возвращенные графы и выяснить, почему эти объекты по-прежнему упоминаются.
Определить, был ли запущен финализатор
Запустите тестовую программу, содержащую следующий код:
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();
Если тест устраняет проблему, это означает, что сборщик мусора не освобождал объекты, так как финализаторы для этих объектов были приостановлены. Метод GC.WaitForPendingFinalizers позволяет финализаторам завершить свои задачи и устраняет проблему.
Определение наличия объектов, ожидающих завершения
В отладчике WinDbg или Visual Studio с загруженным расширением отладчика SOS введите следующую команду:
!finalizequeue
Просмотрите количество объектов, готовых к завершению. Если число большое, необходимо проверить, почему эти финализаторы не могут функционировать совсем или не могут действовать достаточно быстро.
Чтобы получить выходные данные потоков, введите следующую команду:
!threads -special
Эта команда предоставляет выходные данные, например следующие.
OSID Special thread type 2 cd0 DbgHelper 3 c18 Finalizer 4 df0 GC SuspendEE
Поток завершения указывает, какой метод завершения, если таковой имеется, в данный момент выполняется. Если поток финализатора не выполняет методов финализации, он ожидает события, которое даст ему сигнал для выполнения своей работы. Большую часть времени вы увидите поток финализатора в этом состоянии, так как он работает с THREAD_HIGHEST_PRIORITY и должен очень быстро завершить выполнение финализаторов, если они существуют.
Чтобы определить количество свободного места в управляемой куче
В отладчике WinDbg или Visual Studio с загруженным расширением отладчика SOS введите следующую команду:
!dumpheap -type Free -stat
Эта команда отображает общий размер всех свободных объектов в управляемой куче, как показано в следующем примере.
total 230 objects Statistics: MT Count TotalSize Class Name 00152b18 230 40958584 Free Total 230 objects
Чтобы определить свободное пространство в поколении 0, введите следующую команду для сведений о потреблении памяти по поколению:
!eeheap -gc
Эта команда отображает выходные данные, аналогичные приведенному ниже. Последняя строка показывает эфемерный сегмент.
Heap 0 (0015ad08) generation 0 starts at 0x49521f8c generation 1 starts at 0x494d7f64 generation 2 starts at 0x007f0038 ephemeral segment allocation context: none segment begin allocated size 00178250 7a80d84c 7a82f1cc 0x00021980(137600) 00161918 78c50e40 78c7056c 0x0001f72c(128812) 007f0000 007f0038 047eed28 0x03ffecf0(67103984) 3a120000 3a120038 3a3e84f8 0x002c84c0(2917568) 46120000 46120038 49e05d04 0x03ce5ccc(63855820)
Вычислите пространство, используемое поколением 0:
? 49e05d04-0x49521f8c
Результат выглядит следующим образом. Поколение 0 составляет около 9 МБ.
Evaluate expression: 9321848 = 008e3d78
Следующая команда сбрасывает свободное пространство в диапазоне поколения 0:
!dumpheap -type Free -stat 0x49521f8c 49e05d04
Результат выглядит следующим образом.
------------------------------ Heap 0 total 409 objects ------------------------------ Heap 1 total 0 objects ------------------------------ Heap 2 total 0 objects ------------------------------ Heap 3 total 0 objects ------------------------------ total 409 objects Statistics: MT Count TotalSize Class Name 0015a498 409 7296540 Free Total 409 objects
В этом выводе показано, что область кучи поколения 0 использует 9 МБ пространства для объектов и имеет свободные 7 МБ. Этот анализ показывает степень, в которой поколение 0 способствует фрагментации. Это количество использования кучи должно быть вычтено из общего объема, поскольку являет причиной фрагментации долгосрочными объектами.
Определение количества закрепленных объектов
В отладчике WinDbg или Visual Studio с загруженным расширением отладчика SOS введите следующую команду:
!gchandles
Статистика, отображаемая, включает количество закрепленных дескрипторов, как показано в следующем примере.
GC Handle Statistics: Strong Handles: 29 Pinned Handles: 10
Определение длительности процесса сборки мусора
% Time in GC
Проверьте счетчик производительности памяти.Значение вычисляется с помощью временного интервала выборки. Так как счетчики обновляются в конце каждой сборки мусора, текущее значение будет иметь то же значение, что и предыдущее значение, если в течение интервала не произошли сборки.
Время сбора получается путем умножения интервала выборки с процентным значением.
Следующие данные показывают четыре интервала выборки в два секунды для 8-секундного исследования. Столбцы
Gen0
,Gen1
иGen2
показывают общее количество сборок мусора, завершенных к концу интервала для данного поколения.Interval Gen0 Gen1 Gen2 % Time in GC 1 9 3 1 10 2 10 3 1 1 3 11 3 1 3 4 11 3 1 3
Эта информация не показывает, когда произошла сборка мусора, но можно определить количество сборок мусора, которые произошли в течение интервала времени. Предположим, что в худшем случае десятое поколение 0 сборки мусора закончилось в начале второго интервала, а одиннадцатое поколение 0 сборки мусора закончилось в конце третьего интервала. Время между окончанием десятой и одиннадцатой сборок мусора составляет около 2 секунд, а счетчик производительности показывает 3%, так что продолжительность сборки мусора поколения 0 по окончании одиннадцатой сборки составила (2 секунды * 3% = 60 мс).
В следующем примере существует пять интервалов.
Interval Gen0 Gen1 Gen2 % Time in GC 1 9 3 1 3 2 10 3 1 1 3 11 4 1 1 4 11 4 1 1 5 11 4 2 20
Сборка мусора второго поколения началась в течение четвертого интервала и закончилась в течение пятого интервала. Предполагая худший случай, последняя сборка мусора была для коллекции поколения 0, которая закончилась в начале третьего интервала, и сборка мусора поколения 2 закончилась в конце пятого интервала. Поэтому время между окончанием сборки мусора поколения 0 и окончанием сборки мусора поколения 2 составляет 4 секунды. Поскольку счетчик
% Time in GC
равен 20%, максимальное время, которое могла бы занять сборка мусора 2-го поколения, составляет 4 секунды * 20% = 800 мс.Кроме того, можно определить длину сборки мусора с помощью событий трассировки мусора и проанализировать информацию, чтобы определить длительность сборки мусора.
Например, в следующих данных показана последовательность событий, которая произошла во время не одновременной сборки мусора.
Timestamp Event name 513052 GCSuspendEEBegin_V1 513078 GCSuspendEEEnd 513090 GCStart_V1 517890 GCEnd_V1 517894 GCHeapStats 517897 GCRestartEEBegin 517918 GCRestartEEEnd
Время приостановки управляемого потока составило 26 мкс (
GCSuspendEEEnd
–GCSuspendEEBegin_V1
).Фактическая сборка мусора заняла 4,8 мс (
GCEnd_V1
–GCStart_V1
).Возобновление управляемых потоков заняло 21us (
GCRestartEEEnd
–GCRestartEEBegin
).Приведенные ниже выходные данные содержат пример для процесса фоновой сборки мусора и включают поля, относящиеся к процессу, потоку и событию. (Не все данные показаны.)
timestamp(us) event name process thread event field 42504385 GCSuspendEEBegin_V1 Test.exe 4372 1 42504648 GCSuspendEEEnd Test.exe 4372 42504816 GCStart_V1 Test.exe 4372 102019 42504907 GCStart_V1 Test.exe 4372 102020 42514170 GCEnd_V1 Test.exe 4372 42514204 GCHeapStats Test.exe 4372 102020 42832052 GCRestartEEBegin Test.exe 4372 42832136 GCRestartEEEnd Test.exe 4372 63685394 GCSuspendEEBegin_V1 Test.exe 4744 6 63686347 GCSuspendEEEnd Test.exe 4744 63784294 GCRestartEEBegin Test.exe 4744 63784407 GCRestartEEEnd Test.exe 4744 89931423 GCEnd_V1 Test.exe 4372 102019 89931464 GCHeapStats Test.exe 4372
Событие
GCStart_V1
на 42504816 указывает, что это фоновая очистка мусора, так как последнее поле — это1
. Это становится коллекцией мусора № 102019.Это
GCStart
событие возникает из-за необходимости в эфемерной сборке мусора перед началом фоновой сборки мусора. Это становится сбором мусора № 102020.По адресу 42514170 сборка мусора № 102020 завершена. Управляемые потоки перезапускаются на этом этапе. Это выполнено в потоке 4372, который инициировал эту фоновую сборку мусора.
В потоке 4744 происходит приостановка. Это единственный раз, когда фоновая сборка мусора должна приостановить управляемые потоки. Эта длительность составляет примерно 99 мс ((6378407-63685394)/1000.
Событие
GCEnd
для фоновой сборки мусора зарегистрировано на уровне 89931423. Это означает, что фоновая сборка мусора длилась около 47 секунд ((89931423-42504816)/1000).Пока выполняются управляемые потоки, можно увидеть любое количество кратковременных сборок мусора.
Определение того, что активировало сборку мусора
В отладчике WinDbg или Visual Studio с загруженным расширением отладчика SOS введите следующую команду, чтобы отобразить все потоки со стеками вызовов:
~*бк
Эта команда отображает выходные данные, аналогичные приведенному ниже.
0012f3b0 79ff0bf8 mscorwks!WKS::GCHeap::GarbageCollect 0012f454 30002894 mscorwks!GCInterface::CollectGeneration+0xa4 0012f490 79fa22bd fragment_ni!request.Main(System.String[])+0x48
Если сборка мусора вызвана уведомлением операционной системы о нехватке памяти, стек вызовов аналогичен, но поток является потоком финализатора. Поток завершения получает асинхронное уведомление о низком уровне памяти и инициирует сборку мусора.
Если сборка мусора была вызвана выделением памяти, стек отображается следующим образом:
0012f230 7a07c551 mscorwks!WKS::GCHeap::GarbageCollectGeneration 0012f2b8 7a07cba8 mscorwks!WKS::gc_heap::try_allocate_more_space+0x1a1 0012f2d4 7a07cefb mscorwks!WKS::gc_heap::allocate_more_space+0x18 0012f2f4 7a02a51b mscorwks!WKS::GCHeap::Alloc+0x4b 0012f310 7a02ae4c mscorwks!Alloc+0x60 0012f364 7a030e46 mscorwks!FastAllocatePrimitiveArray+0xbd 0012f424 300027f4 mscorwks!JIT_NewArr1+0x148 000af70f 3000299f fragment_ni!request..ctor(Int32, Single)+0x20c 0000002a 79fa22bd fragment_ni!request.Main(System.String[])+0x153
Помощник, работающий по принципу "точно в срок" (
JIT_New*
), в конечном итоге вызываетGCHeap::GarbageCollectGeneration
. Если определить, что сборки мусора поколения 2 вызваны выделениями, необходимо определить, какие объекты собираются сборкой мусора поколения 2 и как избежать их. То есть необходимо определить разницу между началом и окончанием сборки мусора поколения 2 и объектами, вызвавших коллекцию поколения 2.Например, введите следующую команду в отладчике, чтобы отобразить начало коллекции поколения 2:
!dumpheap –stat
Пример выходных данных (сокращенный для отображения объектов, использующих наибольшее пространство):
79124228 31857 9862328 System.Object[] 035f0384 25668 11601936 Toolkit.TlkPosition 00155f80 21248 12256296 Free 79103b6c 297003 13068132 System.Threading.ReaderWriterLock 7a747ad4 708732 14174640 System.Collections.Specialized.HybridDictionary 7a747c78 786498 15729960 System.Collections.Specialized.ListDictionary+DictionaryNode 7a747bac 700298 19608344 System.Collections.Specialized.ListDictionary 035f0ee4 89192 38887712 Toolkit.TlkOrder 00fcae40 6193 44911636 WaveBasedStrategy.Tick_Snap[] 7912c444 91616 71887080 System.Double[] 791242ec 32451 82462728 System.Collections.Hashtable+bucket[] 790fa3e0 2459154 112128436 System.String Total 6471774 objects
Повторите команду в конце поколения 2:
!dumpheap –stat
Пример выходных данных (сокращенный для отображения объектов, использующих наибольшее пространство):
79124228 26648 9314256 System.Object[] 035f0384 25668 11601936 Toolkit.TlkPosition 79103b6c 296770 13057880 System.Threading.ReaderWriterLock 7a747ad4 708730 14174600 System.Collections.Specialized.HybridDictionary 7a747c78 786497 15729940 System.Collections.Specialized.ListDictionary+DictionaryNode 7a747bac 700298 19608344 System.Collections.Specialized.ListDictionary 00155f80 13806 34007212 Free 035f0ee4 89187 38885532 Toolkit.TlkOrder 00fcae40 6193 44911636 WaveBasedStrategy.Tick_Snap[] 791242ec 32370 82359768 System.Collections.Hashtable+bucket[] 790fa3e0 2440020 111341808 System.String Total 6417525 objects
Исчезновение объектов
double[]
из результирующего вывода означает, что они собраны. Эти объекты составляют около 70 МБ. Остальные объекты не изменились. Поэтому этиdouble[]
объекты были причиной, по которой произошла сборка мусора поколения 2. Следующий шаг — определить, почемуdouble[]
объекты там и почему они умерли. Вы можете попросить разработчика кода, откуда пришли эти объекты, или использоватьgcroot
команду.
Определение того, вызвана ли высокая загрузка ЦП сборкой мусора
Сопоставляйте
% Time in GC
значение счетчика производительности памяти со временем процесса.% Time in GC
Если значение резко возрастает одновременно с временем процесса, сборка мусора вызывает высокую загрузку ЦП. В противном случае профилируйте приложение, чтобы найти место, где возникает высокая нагрузка.