Sammeln ausführlicher Informationen zum Laden von Assemblys

Ab .NET 5 kann die Runtime Ereignisse über EventPipe mit detaillierten Informationen über das Laden von verwalteten Assemblys ausgeben, um bei der Diagnose von Problemen beim Laden von Assemblys zu helfen. Diese Ereignisse werden vom Microsoft-Windows-DotNETRuntime-Anbieter unter dem AssemblyLoader-Schlüsselwort (0x4) ausgegeben.

Voraussetzungen

Hinweis

Der Umfang der dotnet-trace-Funktionen ist größer als das Sammeln detaillierter Assemblyladeinformationen. Weitere Informationen zur Nutzung von dotnet-trace finden Sie unter dotnet-trace.

Erfassen einer Ablaufverfolgung mit Assemblyladeereignissen

Sie können dotnet-trace verwenden, um einen vorhandenen Prozess zu verfolgen oder einen untergeordneten Prozess zu starten und ihn vom Start aus zu verfolgen.

Verfolgen eines vorhandenen Prozesses

Verwenden Sie dotnet-trace mit dem folgenden Befehl, um Assemblyladeereignisse in der Runtime zu aktivieren und eine Ablaufverfolgung zu erfassen:

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

Mit diesem Befehl wird eine Ablaufverfolgung der angegebenen <pid> erfasst, wodurch die AssemblyLoader-Ereignisse im Microsoft-Windows-DotNETRuntime-Anbieter aktiviert werden. Das Ergebnis ist eine .nettrace-Datei.

Verwenden von dotnet-trace, um einen untergeordneten Prozess zu starten und vom Start aus zu verfolgen

Manchmal kann es nützlich sein, eine Ablaufverfolgung eines Prozesses vom Start zu erfassen. Für Apps, die mit .NET 5 oder höher ausgeführt werden, können Sie hierfür dotnet-trace verwenden.

Mit dem folgenden Befehl wird hello.exe mit arg1 und arg2 als Befehlszeilenargumenten gestartet, und der Ablauf wird vom Start der Runtime verfolgt:

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

Sie können die Ablaufverfolgungssammlung beenden, indem Sie die Eingabetaste oder STRG + C drücken. Dadurch wird auch hello.exe geschlossen.

Hinweis

  • Beim Starten von hello.exe über dotnet-trace wird die Eingabe und Ausgabe umgeleitet, und Sie können standardmäßig nicht in der Konsole damit interagieren. Verwenden Sie den --show-child-io-Schalter, um mit stdin und stdout zu interagieren.
  • Wenn Sie das Tool über STRG+C oder SIGTERM beenden, wird sowohl das Tool als auch der untergeordnete Prozess sicher beendet.
  • Wenn der untergeordnete Prozess vor dem Tool beendet wird, wird das Tool ebenfalls beendet, und die Ablaufverfolgung sollte sicher angezeigt werden können.

Anzeigen einer Ablaufverfolgung

Die erfasste Ablaufverfolgungsdatei kann unter Windows mithilfe der Ansicht „Ereignisse“ in PerfView angezeigt werden. Allen Assemblyladeereignissen wird Microsoft-Windows-DotNETRuntime/AssemblyLoader vorangestellt.

Beispiel (unter Windows)

Dies ist ein Beispiel mit Assemblylade-Erweiterungspunkten. Die Anwendung versucht, eine Assembly MyLibrary zu laden, auf die die Anwendung nicht verweist, und die darum in einem Assemblylade-Erweiterungspunkt behandelt werden muss, um erfolgreich geladen zu werden.

Erfassen der Ablaufverfolgung

  1. Navigieren Sie zu dem Verzeichnis, das das heruntergeladene Beispiel enthält. Erstellen Sie die Anwendung mit:

    dotnet build
    
  2. Starten Sie die Anwendung mit Argumenten, die angeben, dass sie anhalten und auf einen Tastendruck warten sollte. Beim Fortsetzen wird sie versuchen, die Assembly im Standard-AssemblyLoadContext zu laden – ohne die für ein erfolgreiches Laden erforderliche Handhabung. Navigieren Sie zum Ausgabeverzeichnis, und führen Sie Folgendes aus:

    AssemblyLoading.exe /d default
    
  3. Suchen Sie die Prozess-ID der Anwendung.

    dotnet-trace ps
    

    In der Ausgabe werden die verfügbaren Prozesse aufgelistet. Beispiel:

    35832 AssemblyLoading C:\src\AssemblyLoading\bin\Debug\net5.0\AssemblyLoading.exe
    
  4. Fügen Sie dotnet-trace der ausgeführten Anwendung hinzu.

    dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
    
  5. Drücken Sie in dem Fenster, in dem die Anwendung ausgeführt wird, eine beliebige Taste, damit das Programm fortgesetzt wird. Die Ablaufverfolgung wird automatisch beendet, nachdem die Anwendung beendet wurde.

Anzeigen der Ablaufverfolgung

Öffnen Sie die erfasste Ablaufverfolgung in PerfView, und öffnen Sie die Ansicht „Ereignisse“. Filtern Sie die Ereignisliste nach Microsoft-Windows-DotNETRuntime/AssemblyLoader-Ereignissen.

PerfView assembly loader filter image

Alle Assemblyladungen, die nach dem Start der Ablaufverfolgung in der Anwendung aufgetreten sind, werden angezeigt. Um den Ladevorgang für die Assembly zu überprüfen, die für dieses Beispiel von Interesse ist – MyLibrary – können wir weitere Filterungen durchführen.

Assemblyladungen

Filtern Sie die Ansicht nach den Start- und Stop-Ereignissen unter Microsoft-Windows-DotNETRuntime/AssemblyLoader mithilfe der Ereignisliste auf der linken Seite. Fügen Sie die Spalten AssemblyName, ActivityID und Success der Ansicht hinzu. Filtern Sie nach Ereignissen, die MyLibrary enthalten.

PerfView Start and Stop events image

Veranstaltungsname AssemblyName Aktivitäts-ID Erfolg
AssemblyLoader/Start MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/
AssemblyLoader/Stop MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/ Falsch

Es sollte ein Start/Stop-Paar mit Success=False für das Stop-Ereignis angezeigt werden, das angibt, dass beim Ladevorgang ein Fehler aufgetreten ist. Beachten Sie, dass die Aktivitäts-ID der beiden Ereignisse identisch ist. Mit der Aktivitäts-ID können aus allen anderen Assemblyladerereignissen die herausgefiltert werden, die diesem Ladevorgang entsprechen.

Aufschlüsselung des Ladeversuchs

Um eine ausführlichere Aufschlüsselung des Ladevorgangs zu erhalten, filtern Sie in der Ansicht mithilfe der Ereignisliste auf der linken Seite die ResolutionAttempted-Ereignisse unter Microsoft-Windows-DotNETRuntime/AssemblyLoader heraus. Fügen Sie die Spalten AssemblyName, Stage und Result der Ansicht hinzu. Filtern Sie Ereignisse mit der Aktivitäts-ID aus dem Start/Stop-Paar heraus.

PerfView ResolutionAttempted events image

Veranstaltungsname AssemblyName Phase Ergebnis
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

Die obigen Ereignisse zeigen an, dass das Assemblyladerprogramm versucht hat, die Assembly durch Suchen im aktuellen Ladekontext aufzulösen, wobei die standardmäßige Testlogik für verwaltete Anwendungsassemblys ausgeführt und Handler für das AssemblyLoadContext.Resolving-Ereignis und für AppDomain.AssemblyResolve aufgerufen wurden. In allen diesen Schritten wurde die Assembly nicht gefunden.

Erweiterungspunkte

Um anzuzeigen, welche Erweiterungspunkte aufgerufen wurden, filtern Sie die Ansicht mithilfe der Ereignisliste auf der linken Seite nach AssemblyLoadContextResolvingHandlerInvoked und AppDomainAssemblyResolveHandlerInvoked unter Microsoft-Windows-DotNETRuntime/AssemblyLoader. Fügen Sie die Spalten AssemblyName und HandlerName der Ansicht hinzu. Filtern Sie Ereignisse mit der Aktivitäts-ID aus dem Start/Stop-Paar heraus.

PerfView extension point events image

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

Die obigen Ereignisse zeigen an, dass ein Handler mit dem Namen OnAssemblyLoadContextResolving für das AssemblyLoadContext.Resolving-Ereignis aufgerufen wurde und ein Handler mit dem Namen OnAppDomainAssemblyResolve für das AppDomain.AssemblyResolve-Ereignis.

Erfassen einer anderen Ablaufverfolgung

Führen Sie die Anwendung mit Argumenten aus, sodass der Handler für das AssemblyLoadContext.Resolving-Ereignis die MyLibrary-Assembly lädt.

AssemblyLoading /d default alc-resolving

Erfassen und öffnen Sie eine andere .nettrace-Datei mithilfe der obigen Schritte.

Filtern Sie erneut die Start- und Stop-Ereignisse für MyLibrary. Es sollte ein Start/Stop-Paar mit anderem Start/Stop angezeigt werden. Der innere Ladevorgang stellt die Ladung dar, die vom Handler für AssemblyLoadContext.Resolving ausgelöst wurde, als AssemblyLoadContext.LoadFromAssemblyPath aufgerufen wurde. Jetzt sollte Success=True für das Stop-Ereignis angezeigt werden, um anzugeben, dass der Ladevorgang erfolgreich war. Das ResultAssemblyPath-Feld zeigt den Pfad der resultierenden Assembly an.

PerfView successful Start and Stop events image

Veranstaltungsname AssemblyName Aktivitäts-ID Erfolg 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/ Richtig C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll
AssemblyLoader/Stop MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/ Richtig C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll

Wir können dann die ResolutionAttempted-Ereignisse mit der Aktivitäts-ID aus der äußeren Ladung betrachten, um den Schritt zu ermitteln, in dem die Assembly erfolgreich aufgelöst wurde. Dieses Mal zeigen die Ereignisse an, dass die AssemblyLoadContextResolvingEvent-Phase erfolgreich war. Das ResultAssemblyPath-Feld zeigt den Pfad der resultierenden Assembly an.

PerfView successful ResolutionAttempted events image

Veranstaltungsname AssemblyName Phase Ergebnis 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 zeigt, dass der Handler mit dem Namen OnAssemblyLoadContextResolving aufgerufen wurde. Das ResultAssemblyPath-Feld zeigt den Pfad der vom Handler zurückgegebenen Assembly an.

PerfView successful extension point events image

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

Beachten Sie, dass kein ResolutionAttempted-Ereignis mit der AppDomainAssemblyResolveEvent-Phase oder AppDomainAssemblyResolveHandlerInvoked-Ereignisse mehr vorhanden sind, da die Assembly erfolgreich geladen wurde, bevor der Schritt des Ladealgorithmus erreicht wurde, der das AppDomain.AssemblyResolve-Ereignis auslöst.

Weitere Informationen