アセンブリの読み込みに関する詳細情報の収集
.NET 5 以降、ランタイムを使用して、EventPipe
を介してマネージド アセンブリの読み込みに関する詳細情報を含むイベントを発行し、アセンブリの読み込みに関する問題の診断に役立てることができるようになりました。 これらのイベントは、AssemblyLoader
キーワード (0x4
) に従い Microsoft-Windows-DotNETRuntime
プロバイダーによって発行されます。
前提条件
- .NET 5 SDK 以降のバージョン
dotnet-trace
ツール
注意
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
を使用してこれを行うことができます。
次のコマンドではそのコマンド ライン引数として arg1
と arg2
を受け取って hello.exe が起動し、そのランタイム起動からトレースが収集されます。
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 -- hello.exe arg1 arg2
Enter キーか Ctrl + C キーを押すことでトレース収集を停止できます。hello.exe も終了します。
注意
dotnet-trace
経由で hello.exe を起動するとその入力と出力がリダイレクトされます。既定では、コンソール上ではそれとやり取りできません。 そのstdin
とstdout
とやりとりするには--show-child-io
スイッチを使用します。- Ctrl+C キーまたは
SIGTERM
を介してツールを終了すると、ツールと子プロセスの両方が安全に終了します。 - ツールの前に子プロセスが終了すると、ツールも終了し、トレースを安全に表示できるようになります。
トレースを表示する
収集されたトレース ファイルは、Windows 上で PerfView の [Events](イベント) ビューを使用して表示できます。 すべてのアセンブリの読み込みイベントには、Microsoft-Windows-DotNETRuntime/AssemblyLoader
というプレフィックスが付きます。
例 (Windows の場合)
この例では、アセンブリの読み込み拡張ポイントのサンプルを使用します。 このアプリケーションにより、アセンブリ MyLibrary
(アプリケーションから参照されていないアセンブリ) の読み込みが試行されます。そのため、正常に読み込むには、アセンブリの読み込み拡張ポイントでの処理が必要です。
トレースを収集する
ダウンロードしたサンプルのあるディレクトリに移動します。 次を使用してアプリケーションをビルドします。
dotnet build
一時停止する必要があることを示す引数を指定してアプリケーションを起動し、キーの押下を待機します。 再開すると、既定の
AssemblyLoadContext
でアセンブリの読み込みが試行されます。正常に読み込むために必要な処理は行われません。 出力ディレクトリに移動し、次を実行します。AssemblyLoading.exe /d default
アプリケーションのプロセス ID を見つけます。
dotnet-trace ps
出力には、使用できるプロセスが一覧表示されます。 次に例を示します。
35832 AssemblyLoading C:\src\AssemblyLoading\bin\Debug\net5.0\AssemblyLoading.exe
実行中のアプリケーションに
dotnet-trace
をアタッチします。dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
アプリケーションを実行しているウィンドウで、任意のキーを押してプログラムを続行します。 アプリケーションが終了すると、トレースは自動的に停止します。
トレースを表示する
収集したトレースを PerfView で開き、[Events](イベント) ビューを開きます。 イベント一覧をフィルター処理して Microsoft-Windows-DotNETRuntime/AssemblyLoader
イベントを表示します。
トレースの開始後にアプリケーションで発生したすべてのアセンブリの読み込みが表示されます。 この例 (MyLibrary
) の対象となるアセンブリの読み込み操作を調べるために、さらにフィルター処理を実行することができます。
アセンブリの読み込み
左側のイベント一覧を使用し、ビューをフィルター処理して 以下の Start
および Microsoft-Windows-DotNETRuntime/AssemblyLoader
Stop
イベントを表示します。 列 AssemblyName
、ActivityID
、および Success
をビューに追加します。 フィルター処理して MyLibrary
を含むイベントを表示します。
イベント名 | 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
イベントを表示します。 列 AssemblyName
、Stage
、および Result
をビューに追加します。 フィルター処理して、Start
/Stop
ペアのうち、そのアクティビティ ID を持つイベントを表示します。
イベント名 | 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/AssemblyLoader
AppDomainAssemblyResolveHandlerInvoked
を表示します。 列 AssemblyName
および HandlerName
をビューに追加します。 フィルター処理して、Start
/Stop
ペアのうち、そのアクティビティ ID を持つイベントを表示します。
イベント名 | 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
ファイルを収集して開きます。
フィルター処理して MyLibrary
の Start
および Stop
イベントをもう一度表示します。 Start
/Stop
のペアとその間に別の Start
/Stop
があります。 内側にある読み込み操作は、AssemblyLoadContext.LoadFromAssemblyPath が呼び出されたときに AssemblyLoadContext.Resolving のハンドラーによってトリガーされた読み込みを表します。 今回は、Stop
イベントに Success=True
があります。これは読み込み操作が成功したことを示しています。 ResultAssemblyPath
フィールドには、結果のアセンブリのパスが表示されます。
イベント名 | 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
フィールドには、結果のアセンブリのパスが表示されます。
イベント名 | 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
フィールドには、ハンドラーから返されたアセンブリのパスが表示されます。
イベント名 | 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
イベントは存在しないことに注意してください。
関連項目
.NET