Compartilhar via


Coletar informações detalhadas de carregamento de assembly

Do .NET 5 em diante, o runtime pode emitir eventos por meio de EventPipe com informações detalhadas sobre o carregamento de assembly gerenciado para ajudar no diagnóstico de problemas de carregamento de assembly. Esses eventos são emitidos pelo provedor Microsoft-Windows-DotNETRuntime sob a palavra-chave AssemblyLoader (0x4).

Pré-requisitos

Observação

O escopo de funcionalidades de dotnet-trace é maior do que coletar informações detalhadas de carregamento de assembly. Para obter mais informações sobre o uso de dotnet-trace, confira dotnet-trace.

Coletar um rastreamento com eventos de carregamento de assembly

Você pode usar dotnet-trace para rastrear um processo existente ou iniciar um processo filho e rastreá-lo desde a inicialização.

Rastrear um processo existente

Para habilitar eventos de carregamento de assembly em tempo de execução e coletar um rastreamento deles, use dotnet-trace com o seguinte comando:

dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id <pid>

Esse comando coleta um rastreamento do <pid> especificado habilitando os eventos de AssemblyLoader no provedor Microsoft-Windows-DotNETRuntime. O resultado é um arquivo .nettrace.

Usar o dotnet-trace para iniciar um processo filho e rastreá-lo desde a inicialização

Às vezes, pode ser útil coletar o rastreamento de um processo desde a inicialização. Para aplicativos que executam o .NET 5 ou posterior, você pode usar dotnet-trace para fazer isso.

O seguinte comando inicia hello.exe com arg1 e arg2 como argumentos de linha de comando e coleta um rastreamento desde a inicialização em tempo de execução:

dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 -- hello.exe arg1 arg2

Você pode parar de coletar o rastreamento pressionando Enter ou Ctrl + C. Isso também fecha o hello.exe.

Observação

  • A inicialização de hello.exe por meio de dotnet-trace redireciona as respectivas entradas e saídas e você não pode interagir com ele no console por padrão. Use a opção --show-child-io para interagir com as respectivas stdin e stdout.
  • O encerramento da ferramenta por meio de Ctrl+C ou SIGTERM encerra com segurança a ferramenta e o processo filho.
  • Se o processo filho for encerrado antes da ferramenta, a ferramenta também será encerrada e o rastreamento será exibido com segurança.

Exibir um rastreamento

O arquivo de rastreamento coletado pode ser exibido no Windows usando a exibição Eventos no PerfView. Todos os eventos de carregamento de assembly serão prefixados com Microsoft-Windows-DotNETRuntime/AssemblyLoader.

Exemplo (no Windows)

Este exemplo usa a amostra de pontos de extensão de carregamento de assembly. O aplicativo tenta carregar um assembly MyLibrary – Um assembly que não é referenciado pelo aplicativo e, portanto, requer o processamento de um ponto de extensão de carregamento de assembly para que ele seja carregado com êxito.

Coletar o rastreamento

  1. Navegue até o diretório com o exemplo baixado. Compile o aplicativo com:

    dotnet build
    
  2. Inicie o aplicativo com argumentos que indicam que ele deve ser pausado, aguardando um pressionamento de tecla. Na retomada, ele tentará carregar o assembly no padrão AssemblyLoadContext – Sem o processamento necessário para o sucesso do carregamento. Acesse o diretório de saída e execute:

    AssemblyLoading.exe /d default
    
  3. Localize a ID do processo de aplicativo.

    dotnet-trace ps
    

    A saída listará os processos disponíveis. Por exemplo:

    35832 AssemblyLoading C:\src\AssemblyLoading\bin\Debug\net5.0\AssemblyLoading.exe
    
  4. Anexe dotnet-trace ao aplicativo em execução.

    dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
    
  5. Na janela que executa o aplicativo, pressione qualquer tecla para permitir que o programa continue. O rastreamento será interrompido automaticamente quando o aplicativo for encerrado.

Exibir o rastreamento

Abra o rastreamento coletado no PerfView e abra a exibição Eventos. Filtre a lista de eventos para eventos de Microsoft-Windows-DotNETRuntime/AssemblyLoader.

PerfView assembly loader filter image

Todos os carregamentos de assembly que ocorreram no aplicativo após o rastreamento iniciado serão mostrados. Para inspecionar a operação de carregamento do assembly deste exemplo, MyLibrary, podemos aplicar mais filtragens.

Carregamentos de assembly

Filtre a exibição para os eventos Start e Stop em Microsoft-Windows-DotNETRuntime/AssemblyLoader usando a lista de eventos à esquerda. Adicione as colunas AssemblyName, ActivityID e Success à exibição. Filtre eventos que contenham MyLibrary.

PerfView Start and Stop events image

Nome do evento AssemblyName ActivityID Sucesso
AssemblyLoader/Start MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/
AssemblyLoader/Stop MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/ Falso

Você verá um par de Start/Stop com Success=False no evento Stop, indicando que a operação de carregamento falhou. Observe que os dois eventos têm a mesma ID de atividade. A ID da atividade pode ser usada para filtrar todos os outros eventos do carregador de assembly apenas aos correspondentes a essa operação de carregamento.

Detalhamento da tentativa de carregamento

Para obter um detalhamento maior da operação de carregamento, filtre a exibição para os eventos ResolutionAttempted em Microsoft-Windows-DotNETRuntime/AssemblyLoader usando a lista de eventos à esquerda. Adicione as colunas AssemblyName, Stage e Result à exibição. Filtre eventos com a ID da atividade do par Start/Stop.

PerfView ResolutionAttempted events image

Nome do evento AssemblyName Estágio Result
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

Os eventos acima indicam que o carregador de assembly tentou resolver o assembly examinando o contexto de carregamento atual, executando a lógica de investigação padrão para assemblies de aplicativos gerenciados, invocando manipuladores para o evento AssemblyLoadContext.Resolving e invocando manipuladores para o AppDomain.AssemblyResolve. Para todas essas etapas, o assembly não foi encontrado.

Pontos de extensão

Para ver quais pontos de extensão foram invocados, filtre a exibição para o AssemblyLoadContextResolvingHandlerInvoked e AppDomainAssemblyResolveHandlerInvoked em Microsoft-Windows-DotNETRuntime/AssemblyLoader usando a lista de eventos à esquerda. Adicione as colunas AssemblyName e HandlerName à exibição. Filtre eventos com a ID da atividade do par Start/Stop.

PerfView extension point events image

Nome do evento AssemblyName HandlerName
AssemblyLoader/AssemblyLoadContextResolvingHandlerInvoked MyLibrary, Culture=neutral, PublicKeyToken=null OnAssemblyLoadContextResolving
AssemblyLoader/AppDomainAssemblyResolveHandlerInvoked MyLibrary, Culture=neutral, PublicKeyToken=null OnAppDomainAssemblyResolve

Os eventos acima indicam que um manipulador chamado OnAssemblyLoadContextResolving foi invocado para o evento AssemblyLoadContext.Resolving e um manipulador chamado OnAppDomainAssemblyResolve foi invocado para o evento AppDomain.AssemblyResolve.

Coletar outro rastreamento

Execute o aplicativo com argumentos para que o manipulador do evento AssemblyLoadContext.Resolving carregue o assembly MyLibrary.

AssemblyLoading /d default alc-resolving

Colete e abra outro arquivo .nettrace seguindo as etapas acima.

Filtre apenas os eventos Start e Stop para MyLibrary novamente. Você verá um par Start/Stop com outro Start/Stop entre eles. A operação interna de carregamento representa o carregamento disparado pelo manipulador para AssemblyLoadContext.Resolving quando ele chamou AssemblyLoadContext.LoadFromAssemblyPath. Desta vez, você verá Success=True no evento Stop, indicando que a operação de carregamento foi bem-sucedida. O campo ResultAssemblyPath mostra o caminho do assembly resultante.

PerfView successful Start and Stop events image

Nome do evento AssemblyName ActivityID Sucesso 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/ True C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll
AssemblyLoader/Stop MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/ True C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll

Depois, podemos examinar os eventos ResolutionAttempted com a ID da atividade do carregamento externo para determinar a etapa na qual o assembly foi resolvido com êxito. Desta vez, os eventos mostrarão que a fase AssemblyLoadContextResolvingEvent foi bem sucedida. O campo ResultAssemblyPath mostra o caminho do assembly resultante.

PerfView successful ResolutionAttempted events image

Nome do evento AssemblyName Estágio Result 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

Ao examinar os eventos AssemblyLoadContextResolvingHandlerInvoked, veja que o manipulador chamado OnAssemblyLoadContextResolving foi invocado. O campo ResultAssemblyPath mostra o caminho do assembly retornado pelo manipulador.

PerfView successful extension point events image

Nome do evento AssemblyName HandlerName ResultAssemblyPath
AssemblyLoader/AssemblyLoadContextResolvingHandlerInvoked MyLibrary, Culture=neutral, PublicKeyToken=null OnAssemblyLoadContextResolving C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll

Observe que não há mais um evento ResolutionAttempted com a fase AppDomainAssemblyResolveEvent nem eventos AppDomainAssemblyResolveHandlerInvoked, pois o assembly foi carregado com êxito antes de chegar à fase do algoritmo de carregamento que gera o evento AppDomain.AssemblyResolve.

Confira também