收集詳盡的組件載入資訊
從 .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>
這項命令會收集指定 <pid>
的追蹤,並啟用 Microsoft-Windows-DotNETRuntime
提供者內的 AssemblyLoader
事件。 其結果為 .nettrace
檔案。
用 dotnet-trace 啟動子處理序並從啟動時予以追蹤
有時候從啟動收集處理序追蹤很有用。 針對執行 .NET 5 或更新版本的應用程式,您可使用 dotnet-trace
來進行。
下列命令會在啟動 hello.exe 時以 arg1
和 arg2
作為命令列引數,並從執行階段啟動時收集追蹤:
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 -- hello.exe arg1 arg2
您可按下 [Enter] 或 [Ctrl + C] 鍵來停止收集追蹤。這也會關閉 hello.exe。
注意
- 透過
dotnet-trace
啟動 hello.exe 會重新導向其輸入與輸出,根據預設,您將無法在主控台上與之互動。 請用--show-child-io
參數來與其stdin
和stdout
互動。 - 透過 Ctrl+C 結束工具,或透過
SIGTERM
同時安全地結束工具和子處理序。 - 如果子處理序在工具之前結束,則工具也會結束,您應可安全地檢視追蹤。
檢視追蹤
收集到的追蹤檔案可透過 PerfView 中的 [事件檢視] 在 Windows 上查看。 所有組件載入事件都會加上 Microsoft-Windows-DotNETRuntime/AssemblyLoader
前置詞。
範例 (在 Windows 上)
此範例運用組件載入擴充點範例。 應用程式試圖載入 MyLibrary
組件,該組件未受應用程式參考,因此需在組件載入擴充點中處理,才能成功載入。
收集追蹤
使用下載的範例瀏覽至目錄。 使用以下程式碼組建應用程式:
dotnet build
使用指定應暫停並等候按鍵的引數啟動應用程式。 繼續後,系統會試圖在預設的
AssemblyLoadContext
中載入組件,此時並未進行成功載入所需的處理流程。 瀏覽至輸出目錄並執行以下程式碼:AssemblyLoading.exe /d default
找到應用程式的流程識別碼。
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 中開啟收集到的追蹤,並開啟 [事件檢視]。 將事件清單篩選為 Microsoft-Windows-DotNETRuntime/AssemblyLoader
事件。
系統會顯示所有啟動追蹤後在應用程式內發生的組件載入活動。 若要為此範例的重點組件 MyLibrary
檢查載入作業,我們可以進一步進行篩選。
組件載入
使用左側的事件清單,將檢視表篩選為 Microsoft-Windows-DotNETRuntime/AssemblyLoader
下的 Start
和 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
事件上看到一個有 Success=False
的 Start
/Stop
配對,表示載入作業失敗。 請注意,這兩個事件有相同的活動識別碼。 活動識別碼可用來將其他所有組件載入器事件,篩選為只包含此載入作業的對應項目。
載入意圖的細項
如需載入作業的更多細項,請用左側的事件清單將檢視表篩選為 Microsoft-Windows-DotNETRuntime/AssemblyLoader
下的 ResolutionAttempted
事件。 在檢視表中新增 AssemblyName
、Stage
和 Result
資料行。 用 Start
/Stop
配對的活動識別碼篩選事件。
事件名稱 | 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 叫用處理常式來解析組件。 執行過這所有步驟之後,仍然找不到組件。
擴充點
若要查看所叫用的擴充點,請用左側的事件清單將檢視表篩選為 Microsoft-Windows-DotNETRuntime/AssemblyLoader
下的 AssemblyLoadContextResolvingHandlerInvoked
和 AppDomainAssemblyResolveHandlerInvoked
。 在檢視表中新增 AssemblyName
和 HandlerName
資料行。 用 Start
/Stop
配對的活動識別碼篩選事件。
事件名稱 | AssemblyName | HandlerName |
---|---|---|
AssemblyLoader/AssemblyLoadContextResolvingHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAssemblyLoadContextResolving |
AssemblyLoader/AppDomainAssemblyResolveHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAppDomainAssemblyResolve |
上述事件表示系統針對 AssemblyLoadContext.Resolving 事件叫用了名為 OnAssemblyLoadContextResolving
的處理常式,並針對 AppDomain.AssemblyResolve 事件叫用了名為 OnAppDomainAssemblyResolve
的處理常式。
收集另一個追蹤
用引數執行應用程式,好使 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 |
之後我們可查看活動識別碼來自外部載入的 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 |
請注意,系統沒有處於 AppDomainAssemblyResolveEvent
階段的 ResolutionAttempted
事件或任何 AppDomainAssemblyResolveHandlerInvoked
事件,因為組件已在觸達引發 AppDomain.AssemblyResolve 事件的載入演算法步驟前成功載入。