Сбор подробных сведений о загрузке сборок
Начиная с .NET 5 среда выполнения может создавать с помощью EventPipe
события с подробными сведениями о загрузке управляемой сборки, которые упрощают диагностику проблем с загрузкой сборок. Такие события выдаются поставщиком Microsoft-Windows-DotNETRuntime
с ключевым словом AssemblyLoader
(0x4
).
Необходимые компоненты
- Пакет SDK для .NET 5 или более поздней версии.
- Средство
dotnet-trace
Примечание.
Область возможностей dotnet-trace
больше, чем сбор подробных сведений о загрузке сборки. Дополнительные сведения об использовании dotnet-trace
см. здесь: dotnet-trace
.
Сбор трассировки с помощью событий загрузки сборок
Можно использовать dotnet-trace
для трассировки существующего процесса или запуска дочернего процесса и трассировки его с момента запуска.
Трассировка существующего процесса
Чтобы включить события загрузки сборок в среде выполнения и собирать для них трассировки, используйте dotnet-trace
с помощью следующей команды:
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id <pid>
Эта команда собирает данные трассировки указанного <pid>
, активируя события AssemblyLoader
в поставщике Microsoft-Windows-DotNETRuntime
. Результатом будет файл .nettrace
.
Использование команды dotnet-trace для запуска дочернего процесса и его трассировки при запуске
Иногда бывает полезно получить трассировку процесса от запуска. Для приложений, использующих .NET 5 или более поздней версии, для этого можно использовать dotnet-trace
.
Следующая команда запускает hello.exe с arg1
и arg2
в качестве аргументов командной строки и собирает данные трассировки при запуске среды выполнения:
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 -- hello.exe arg1 arg2
Вы можете отключить сбор данных трассировки, нажав клавиши ВВОД или CTRL + C. Это также закрывает hello.exe.
Примечание.
- При запуске hello.exe с помощью
dotnet-trace
входные и выходные данные будут перенаправлены, и вы не сможете взаимодействовать с ними в консоли по умолчанию. Используйте параметр--show-child-io
, чтобы взаимодействовать сstdin
иstdout
. - Выход из средства с помощью клавиш CTRL+C или
SIGTERM
приведет к безопасному завершению работы средства и дочернего процесса. - Если дочерний процесс завершает работу раньше средства, средство также завершит работу, а трассировка будет доступна для безопасного просмотра.
Просмотр трассировки
Собранный файл трассировки можно просмотреть в Windows с помощью представления "События" в PerfView. Все события загрузки сборок будут иметь префикс Microsoft-Windows-DotNETRuntime/AssemblyLoader
.
Пример (в Windows)
Здесь используется пример точек расширения загрузки сборок. Приложение пытается загрузить сборку MyLibrary
, на которую не ссылается приложение и которая поэтому требует обработки в точке расширения загрузки сборок для успешной загрузки.
Сбор трассировки
Перейдите к каталогу со скачанным примером. Выполните сборку приложения с помощью команды:
dotnet build
Запустите приложение с аргументами для приостановки и ожидания нажатия клавиши. При возобновлении приложение попытается загрузить сборку
AssemblyLoadContext
по умолчанию, без обработки для успешной загрузки. Перейдите к выходному каталогу и выполните команду:AssemblyLoading.exe /d default
Найдите идентификатор процесса приложения.
dotnet-trace ps
В выходных данных будут указаны доступные процессы. Например:
35832 AssemblyLoading C:\src\AssemblyLoading\bin\Debug\net5.0\AssemblyLoading.exe
Подключите
dotnet-trace
к выполняющемуся приложению.dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
В окне, где выполняется приложение, нажмите любую клавишу, чтобы продолжить выполнение программы. Трассировка будет автоматически прекращена после завершения работы приложения.
Просмотр трассировки
Откройте собранную трассировку в PerfView и откройте представление "События". Отфильтруйте список событий для отображения событий Microsoft-Windows-DotNETRuntime/AssemblyLoader
.
Будут показаны все загрузки сборок, которые были выполнены в приложении после начала трассировки. Чтобы просмотреть операцию загрузки для нужной сборки в этом примере (MyLibrary
), мы можем задать дополнительные фильтры.
Загрузки сборок
Отфильтруйте представление для отображения событий Start
и Stop
в разделе Microsoft-Windows-DotNETRuntime/AssemblyLoader
с помощью списка событий слева. Добавьте к представлению столбцы AssemblyName
, ActivityID
и Success
. Выполните фильтрацию по событиям, содержащим MyLibrary
.
Имя события | AssemblyName | ActivityID | Удачное завершение |
---|---|---|---|
AssemblyLoader/Start |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | |
AssemblyLoader/Stop |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | False |
Вы должны увидеть одну пару Start
/Stop
с Success=False
для события Stop
, что указывает на сбой операции загрузки. Обратите внимание, что два события имеют одинаковый идентификатор действия. Идентификатор действия можно использовать для фильтрации всех остальных событий загрузчика сборок с отображением только тех из них, которые относятся к этой операции загрузки.
Детализация попытки загрузки
Чтобы просмотреть детализацию для операции загрузки, отфильтруйте представления по событиям ResolutionAttempted
в разделе Microsoft-Windows-DotNETRuntime/AssemblyLoader
с помощью списка событий слева. Добавьте к представлению столбцы AssemblyName
, Stage
и Result
. Выполните фильтрацию по событиям с идентификатором действия из пары Start
/Stop
.
Имя события | AssemblyName | Этап | Результат |
---|---|---|---|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
FindInLoadContext |
AssemblyNotFound |
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
ApplicationAssemblies |
AssemblyNotFound |
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
AssemblyLoadContextResolvingEvent |
AssemblyNotFound |
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
AppDomainAssemblyResolveEvent |
AssemblyNotFound |
Приведенные выше события указывают, что загрузчик сборок попытался разрешить сборку путем поиска в текущем контексте загрузки, запуска логики проверки по умолчанию для сборок управляемого приложения, вызова обработчиков для события AssemblyLoadContext.Resolving и вызова обработчиков для AppDomain.AssemblyResolve. При выполнении каждого из этих шагов сборка не была найдена.
Точки расширения
Чтобы узнать, какие точки расширения были вызваны, выполните фильтрацию представления по AssemblyLoadContextResolvingHandlerInvoked
и AppDomainAssemblyResolveHandlerInvoked
в разделе Microsoft-Windows-DotNETRuntime/AssemblyLoader
с помощью списка событий слева. Добавьте к представлению столбцы AssemblyName
и HandlerName
. Выполните фильтрацию по событиям с идентификатором действия из пары Start
/Stop
.
Имя события | AssemblyName | HandlerName |
---|---|---|
AssemblyLoader/AssemblyLoadContextResolvingHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAssemblyLoadContextResolving |
AssemblyLoader/AppDomainAssemblyResolveHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAppDomainAssemblyResolve |
Приведенные выше события указывают на то, что обработчик с именем OnAssemblyLoadContextResolving
был вызван для события AssemblyLoadContext.Resolving, а обработчик с именем OnAppDomainAssemblyResolve
— для события AppDomain.AssemblyResolve.
Сбор дополнительной трассировки
Запустите приложение с аргументами, чтобы обработчик события AssemblyLoadContext.Resolving загружал сборку MyLibrary
.
AssemblyLoading /d default alc-resolving
Соберите и откройте еще один файл .nettrace
, выполнив приведенные выше шаги.
Снова выполните фильтрацию по событиям Start
и Stop
для MyLibrary
. Вы должны увидеть пару Start
/Stop
с Start
/Stop
между ними. Внутренняя операция загрузки представляет загрузку, активируемую обработчиком для AssemblyLoadContext.Resolving при вызове AssemblyLoadContext.LoadFromAssemblyPath. Вы должны увидеть Success=True
для события Stop
, что указывает на успешную операцию загрузки. В поле ResultAssemblyPath
отображается путь к итоговой сборке.
Имя события | AssemblyName | ActivityID | Удачное завершение | ResultAssemblyPath |
---|---|---|---|---|
AssemblyLoader/Start |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | ||
AssemblyLoader/Start |
MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null |
//1/2/1/ | ||
AssemblyLoader/Stop |
MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null |
//1/2/1/ | Истина | C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
AssemblyLoader/Stop |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | Истина | C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
Затем можно просмотреть события ResolutionAttempted
с идентификатором действия из внешней нагрузки, чтобы определить шаг, на котором сборка была успешно разрешена. На этот раз события покажут, что этап AssemblyLoadContextResolvingEvent
был выполнен успешно. В поле ResultAssemblyPath
отображается путь к итоговой сборке.
Имя события | AssemblyName | Этап | Результат | ResultAssemblyPath |
---|---|---|---|---|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
FindInLoadContext |
AssemblyNotFound |
|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
ApplicationAssemblies |
AssemblyNotFound |
|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
AssemblyLoadContextResolvingEvent |
Success |
C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
При просмотре событий AssemblyLoadContextResolvingHandlerInvoked
станет понятно, что был вызван обработчик с именем OnAssemblyLoadContextResolving
. В поле ResultAssemblyPath
отображается путь к сборке, возвращенной обработчиком.
Имя события | AssemblyName | HandlerName | ResultAssemblyPath |
---|---|---|---|
AssemblyLoader/AssemblyLoadContextResolvingHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAssemblyLoadContextResolving |
C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
Обратите внимание, что событие ResolutionAttempted
с этапом AppDomainAssemblyResolveEvent
или какие-либо события AppDomainAssemblyResolveHandlerInvoked
больше не существуют, так как сборка была успешно загружена до достижения шага алгоритма загрузки, вызывающего событие AppDomain.AssemblyResolve.