アセンブリの読み込みに関する詳細情報の収集

.NET 5 以降、ランタイムを使用して、EventPipe を介してマネージド アセンブリの読み込みに関する詳細情報を含むイベントを発行し、アセンブリの読み込みに関する問題の診断に役立てることができるようになりました。 これらのイベントは、AssemblyLoader キーワード (0x4) に従い Microsoft-Windows-DotNETRuntime プロバイダーによって発行されます。

前提条件

注意

dotnet-trace 機能の範囲は、アセンブリの読み込みに関する詳細情報を収集することよりも大きくなります。 dotnet-trace の使用の詳細については、dotnet-trace を参照してください。

アセンブリの読み込みイベントを使用してトレースを収集する

dotnet-trace を使用すると、既存のプロセスをトレースしたり、子プロセスを起動して起動からトレースしたりできます。

既存のプロセスをトレースする

ランタイムでアセンブリの読み込みイベントを有効にし、それらのトレースを収集するには、次のコマンドで dotnet-trace を使用します。

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

このコマンドにより、Microsoft-Windows-DotNETRuntime プロバイダーで AssemblyLoader イベントが有効になり、指定された <pid> のトレースが収集されます。 結果は .nettrace ファイルになります。

dotnet-trace を使用して子プロセスを起動し、起動からそれをトレースする

場合によっては、プロセスのトレースをそのスタートアップから収集すると便利なことがあります。 .NET 5 以降を実行しているアプリでは、dotnet-trace を使用してこれを行うことができます。

次のコマンドではそのコマンド ライン引数として arg1arg2 を受け取って hello.exe が起動し、そのランタイム起動からトレースが収集されます。

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

Enter キーか Ctrl + C キーを押すことでトレース収集を停止できます。hello.exe も終了します。

注意

  • dotnet-trace 経由で hello.exe を起動するとその入力と出力がリダイレクトされます。既定では、コンソール上ではそれとやり取りできません。 その stdinstdout とやりとりするには --show-child-io スイッチを使用します。
  • Ctrl+C キーまたは SIGTERM を介してツールを終了すると、ツールと子プロセスの両方が安全に終了します。
  • ツールの前に子プロセスが終了すると、ツールも終了し、トレースを安全に表示できるようになります。

トレースを表示する

収集されたトレース ファイルは、Windows 上で PerfView の [Events](イベント) ビューを使用して表示できます。 すべてのアセンブリの読み込みイベントには、Microsoft-Windows-DotNETRuntime/AssemblyLoader というプレフィックスが付きます。

例 (Windows の場合)

この例では、アセンブリの読み込み拡張ポイントのサンプルを使用します。 このアプリケーションにより、アセンブリ MyLibrary (アプリケーションから参照されていないアセンブリ) の読み込みが試行されます。そのため、正常に読み込むには、アセンブリの読み込み拡張ポイントでの処理が必要です。

トレースを収集する

  1. ダウンロードしたサンプルのあるディレクトリに移動します。 次を使用してアプリケーションをビルドします。

    dotnet build
    
  2. 一時停止する必要があることを示す引数を指定してアプリケーションを起動し、キーの押下を待機します。 再開すると、既定の AssemblyLoadContext でアセンブリの読み込みが試行されます。正常に読み込むために必要な処理は行われません。 出力ディレクトリに移動し、次を実行します。

    AssemblyLoading.exe /d default
    
  3. アプリケーションのプロセス ID を見つけます。

    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 で開き、[Events](イベント) ビューを開きます。 イベント一覧をフィルター処理して Microsoft-Windows-DotNETRuntime/AssemblyLoader イベントを表示します。

PerfView assembly loader filter image

トレースの開始後にアプリケーションで発生したすべてのアセンブリの読み込みが表示されます。 この例 (MyLibrary) の対象となるアセンブリの読み込み操作を調べるために、さらにフィルター処理を実行することができます。

アセンブリの読み込み

左側のイベント一覧を使用し、ビューをフィルター処理して 以下の Start および Microsoft-Windows-DotNETRuntime/AssemblyLoaderStop イベントを表示します。 列 AssemblyNameActivityID、および 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

Stop イベントに 1 つの Start/Stop ペアと Success=False があります。これは、読み込み操作が失敗したことを示します。 2 つのイベントのアクティビティ ID が同じであることに注意してください。 アクティビティ ID を使用すると、他のすべてのアセンブリ ローダー イベントを、この読み込み操作に対応するイベントのみにフィルター処理することができます。

読み込みの試行の内訳

読み込み操作の詳細な内訳については、左側のイベント一覧を使用し、ビューをフィルター処理して Microsoft-Windows-DotNETRuntime/AssemblyLoader 以下の ResolutionAttempted イベントを表示します。 列 AssemblyNameStage、および Result をビューに追加します。 フィルター処理して、Start/Stop ペアのうち、そのアクティビティ ID を持つイベントを表示します。

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 および Microsoft-Windows-DotNETRuntime/AssemblyLoaderAppDomainAssemblyResolveHandlerInvoked を表示します。 列 AssemblyName および HandlerName をビューに追加します。 フィルター処理して、Start/Stop ペアのうち、そのアクティビティ ID を持つイベントを表示します。

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 ファイルを収集して開きます。

フィルター処理して MyLibraryStart および Stop イベントをもう一度表示します。 Start/Stop のペアとその間に別の Start/Stop があります。 内側にある読み込み操作は、AssemblyLoadContext.LoadFromAssemblyPath が呼び出されたときに AssemblyLoadContext.Resolving のハンドラーによってトリガーされた読み込みを表します。 今回は、Stop イベントに Success=True があります。これは読み込み操作が成功したことを示しています。 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/ 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

次に、外側の読み込みのアクティビティ ID を持つ 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

AppDomain.AssemblyResolve イベントを発生させる読み込みアルゴリズムのステップに到達する前にアセンブリが正常に読み込まれたため、AppDomainAssemblyResolveEvent ステージまたは AppDomainAssemblyResolveHandlerInvoked イベントを伴う ResolutionAttempted イベントは存在しないことに注意してください。

関連項目