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
- .NET 5 SDK o versioni successive
- Strumento
dotnet-trace
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 relativistdin
estdout
. - 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
Passare alla directory con l'esempio scaricato. Compilare l'applicazione con:
dotnet build
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
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
Collegare
dotnet-trace
all'applicazione in esecuzione.dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
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
.
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
.
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
.
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
.
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.
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.
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.
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.