Поделиться через


Сбор подробных сведений о загрузке сборок

Начиная с .NET 5 среда выполнения может создавать с помощью EventPipe события с подробными сведениями о загрузке управляемой сборки, которые упрощают диагностику проблем с загрузкой сборок. Такие события выдаются поставщиком Microsoft-Windows-DotNETRuntime с ключевым словом AssemblyLoader (0x4).

Необходимые компоненты

Примечание.

Область возможностей 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, на которую не ссылается приложение и которая поэтому требует обработки в точке расширения загрузки сборок для успешной загрузки.

Сбор трассировки

  1. Перейдите к каталогу со скачанным примером. Выполните сборку приложения с помощью команды:

    dotnet build
    
  2. Запустите приложение с аргументами для приостановки и ожидания нажатия клавиши. При возобновлении приложение попытается загрузить сборку AssemblyLoadContext по умолчанию, без обработки для успешной загрузки. Перейдите к выходному каталогу и выполните команду:

    AssemblyLoading.exe /d default
    
  3. Найдите идентификатор процесса приложения.

    dotnet-trace ps
    

    В выходных данных будут указаны доступные процессы. Например:

    35832 AssemblyLoading C:\src\AssemblyLoading\bin\Debug\net5.0\AssemblyLoading.exe
    
  4. Подключите dotnet-trace к выполняющемуся приложению.

    dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
    
  5. В окне, где выполняется приложение, нажмите любую клавишу, чтобы продолжить выполнение программы. Трассировка будет автоматически прекращена после завершения работы приложения.

Просмотр трассировки

Откройте собранную трассировку в PerfView и откройте представление "События". Отфильтруйте список событий для отображения событий Microsoft-Windows-DotNETRuntime/AssemblyLoader.

PerfView assembly loader filter image

Будут показаны все загрузки сборок, которые были выполнены в приложении после начала трассировки. Чтобы просмотреть операцию загрузки для нужной сборки в этом примере (MyLibrary), мы можем задать дополнительные фильтры.

Загрузки сборок

Отфильтруйте представление для отображения событий Start и Stop в разделе Microsoft-Windows-DotNETRuntime/AssemblyLoader с помощью списка событий слева. Добавьте к представлению столбцы AssemblyName, ActivityID и Success. Выполните фильтрацию по событиям, содержащим MyLibrary.

PerfView Start and Stop events image

Имя события 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.

PerfView ResolutionAttempted events image

Имя события 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.

PerfView extension point events image

Имя события 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 отображается путь к итоговой сборке.

PerfView successful Start and Stop events image

Имя события 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 отображается путь к итоговой сборке.

PerfView successful ResolutionAttempted events image

Имя события 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 отображается путь к сборке, возвращенной обработчиком.

PerfView successful extension point events image

Имя события 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.

См. также