Raccogliere informazioni dettagliate sul caricamento di assembly

A partire da .NET 5, il runtime può generare eventi tramite EventPipe con informazioni dettagliate sul caricamento di assembly gestiti per facilitare la diagnosi dei problemi di caricamento degli assembly. Questi eventi vengono generati dal provider di Microsoft-Windows-DotNETRuntime sotto la parola chiave AssemblyLoader (0x4).

Prerequisiti

Nota

L'ambito delle funzionalità di dotnet-trace è maggiore della raccolta di informazioni dettagliate sul caricamento di assembly. Per altre informazioni sull'utilizzo di dotnet-trace, vedere dotnet-trace.

Raccogliere una traccia con eventi di caricamento di assembly

È possibile usare dotnet-trace per tracciare un processo esistente o per avviare un processo figlio e tracciarlo dall'avvio.

Tracciare un processo esistente

Per abilitare gli eventi di caricamento degli assembly nel runtime e raccoglierne una traccia, usare dotnet-trace con il comando seguente:

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

Questo comando raccoglie una traccia dell’oggetto <pid> specificato, abilitando gli eventi AssemblyLoader nel provider di Microsoft-Windows-DotNETRuntime. Il risultato è un file .nettrace.

Usare dotnet-trace per avviare un processo figlio e tracciarlo dall'avvio

A volte può essere utile raccogliere una traccia di un processo dall'avvio. Per le app che eseguono .NET 5 o versioni successive, è possibile usare dotnet-trace per eseguire questa operazione.

Il comando seguente avvia hello.exe con arg1 e arg2 come argomenti della riga di comando e raccoglie una traccia dall'avvio del runtime:

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

È possibile interrompere la raccolta della traccia premendo INVIO o CTRL + C. Questo chiude anche hello.exe.

Nota

  • L'avvio di hello.exe tramite dotnet-trace reindirizza l'input e l'output e non sarà possibile interagire con esso nella console per impostazione predefinita. Usare l'opzione --show-child-io per interagire con i relativi stdin e stdout.
  • Uscendo dallo strumento tramite CTRL+C o SIGTERM, termina in modo sicuro sia lo strumento che il processo figlio.
  • Se il processo figlio viene chiuso prima dello strumento, lo strumento viene chiuso e la traccia deve essere visualizzabile in modo sicuro.

Visualizzare una traccia

Il file di traccia raccolto può essere visualizzato in Windows usando la visualizzazione Eventi in PerfView. Tutti gli eventi di caricamento dell'assembly saranno preceduti da Microsoft-Windows-DotNETRuntime/AssemblyLoader.

Esempio (in Windows)

In questo esempio viene usato l'esempio di punti di estensione per il caricamento dell'assembly. L'applicazione tenta di caricare un assembly MyLibrary: un assembly a cui non fa riferimento l'applicazione e pertanto richiede che la gestione in un punto di estensione per il caricamento di assembly venga caricata correttamente.

Raccogliere la traccia

  1. Passare alla directory con l'esempio scaricato. Compilare l'applicazione con:

    dotnet build
    
  2. Avviare l'applicazione con argomenti che indicano che deve essere sospesa, in attesa di premere un tasto. Al termine della ripresa, tenterà di caricare l'assembly nell'impostazione predefinita AssemblyLoadContext, senza la gestione necessaria per un caricamento riuscito. Passare alla directory di output ed eseguire:

    AssemblyLoading.exe /d default
    
  3. Trovare l'ID del processo dell'applicazione.

    dotnet-trace ps
    

    L'output elenca i processi disponibili. Ad esempio:

    35832 AssemblyLoading C:\src\AssemblyLoading\bin\Debug\net5.0\AssemblyLoading.exe
    
  4. Collegare dotnet-trace all'applicazione in esecuzione.

    dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
    
  5. Nella finestra che esegue l'applicazione premere un tasto qualsiasi per consentire al programma di continuare. La traccia verrà interrotta automaticamente al termine dell'applicazione.

Visualizzare la traccia

Aprire la traccia raccolta in PerfView e aprire la visualizzazione Eventi. Filtrare l'elenco di eventi in base agli eventi Microsoft-Windows-DotNETRuntime/AssemblyLoader.

PerfView assembly loader filter image

Verranno visualizzati tutti i carichi di assembly che si sono verificati nell'applicazione dopo l'avvio della traccia. Per esaminare l'operazione di caricamento per l'assembly di interesse per questo esempio, MyLibrary, è possibile eseguire altri filtri.

Caricamenti di assembly

Filtrare la visualizzazione degli eventi Start e Stop in Microsoft-Windows-DotNETRuntime/AssemblyLoader usando l'elenco di eventi a sinistra. Aggiungere le colonne AssemblyName, ActivityID e Success alla visualizzazione. Filtrare in base agli eventi contenenti MyLibrary.

PerfView Start and Stop events image

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

Verrà visualizzata una coppia di Start/Stop con Success=False nell'evento Stop, a indicare che l'operazione di caricamento non è riuscita. Si noti che i due eventi hanno lo stesso ID attività. L'ID attività può essere usato per filtrare tutti gli altri eventi del caricatore di assembly in base a quelli corrispondenti a questa operazione di caricamento.

Scomposizione del tentativo di caricamento

Per una suddivisione più dettagliata dell'operazione di caricamento, filtrare la visualizzazione in base agli eventiResolutionAttempted in Microsoft-Windows-DotNETRuntime/AssemblyLoader usando l'elenco di eventi a sinistra. Aggiungere le colonne AssemblyName, Stage e Result alla visualizzazione. Filtrare gli eventi con l'ID attività dalla coppia Start/Stop.

PerfView ResolutionAttempted events image

Nome evento AssemblyName Fase Risultato
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

Gli eventi precedenti indicano che il caricatore di assembly ha tentato di risolvere l'assembly cercando nel contesto di carico corrente, eseguendo la logica di probe predefinita per gli assembly dell'applicazione gestita, richiamando i gestori per l'evento AssemblyLoadContext.Resolving, e richiamando i gestori per AppDomain.AssemblyResolve. Per tutti questi passaggi, l'assembly non è stato trovato.

Punti di estensione

Per visualizzare i punti di estensione richiamati, filtrare la visualizzazione di AssemblyLoadContextResolvingHandlerInvoked e AppDomainAssemblyResolveHandlerInvoked in Microsoft-Windows-DotNETRuntime/AssemblyLoader usando l'elenco di eventi a sinistra. Aggiungere le colonne AssemblyName e HandlerName alla visualizzazione. Filtrare gli eventi con l'ID attività dalla coppia Start/Stop.

PerfView extension point events image

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

Gli eventi precedenti indicano che è stato richiamato un gestore denominato OnAssemblyLoadContextResolving per l'evento AssemblyLoadContext.Resolving e che è stato richiamato un gestore denominato OnAppDomainAssemblyResolve per l'evento AppDomain.AssemblyResolve.

Raccogliere un'altra traccia

Eseguire l'applicazione con argomenti in modo che il relativo gestore per l'evento AssemblyLoadContext.Resolving caricherà l'assembly MyLibrary.

AssemblyLoading /d default alc-resolving

Raccogliere e aprire un altro file .nettrace usando i passaggi precedenti.

Applicare nuovamente il filtro agli eventi Start e Stop per MyLibrary. Verrà visualizzata una coppia di Start/Stop con un'altra Start/Stop tra di esse. L'operazione di caricamento interno rappresenta il carico attivato dal gestore per AssemblyLoadContext.Resolving quando ha chiamato AssemblyLoadContext.LoadFromAssemblyPath. Questa volta, verrà visualizzato Success=True sull'evento Stop, che indica che l'operazione di caricamento è riuscita. Il campo ResultAssemblyPath mostra il percorso dell'assembly risultante.

PerfView successful Start and Stop events image

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

È quindi possibile esaminare gli eventi ResolutionAttempted con l'ID attività dal carico esterno per determinare il passaggio in cui l'assembly è stato risolto correttamente. Questa volta, gli eventi mostreranno che la fase AssemblyLoadContextResolvingEvent ha avuto esito positivo. Il campo ResultAssemblyPath mostra il percorso dell'assembly risultante.

PerfView successful ResolutionAttempted events image

Nome evento AssemblyName Fase Risultato 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

Esaminando gli eventi AssemblyLoadContextResolvingHandlerInvoked, il gestore denominato OnAssemblyLoadContextResolving è stato richiamato. Il campo ResultAssemblyPath mostra il percorso dell'assembly restituito dal gestore.

PerfView successful extension point events image

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

Si noti che non è più presente un evento ResolutionAttempted con la fase AppDomainAssemblyResolveEvent o gli eventi di AppDomainAssemblyResolveHandlerInvoked, perché l'assembly è stato caricato correttamente prima di raggiungere il passaggio dell'algoritmo di caricamento che genera l'evento AppDomain.AssemblyResolve.

Vedi anche