다음을 통해 공유


자세한 어셈블리 로딩 정보 수집

.NET 5부터 런타임은 어셈블리 로딩 문제를 진단하는 데 도움이 되도록 관리되는 어셈블리 로딩에 대한 자세한 정보와 함께 EventPipe를 통해 이벤트를 내보낼 수 있습니다. 이러한 이벤트Microsoft-Windows-DotNETRuntime 공급자가 AssemblyLoader 키워드(0x4)로 내보냅니다.

필수 조건

참고 항목

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를 사용하여 이 작업을 수행할 수 있습니다.

다음 명령은 arg1arg2를 명령줄 인수로 사용해 hello.exe를 시작하고 런타임 시작부터 추적을 수집합니다.

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

Enter 또는 Ctrl + C를 눌러 추적 수집을 중지할 수 있습니다. 이렇게 하면 hello.exe도 종료됩니다.

참고 항목

  • dotnet-trace를 통해 hello.exe를 실행하면 입력 및 출력이 리디렉션되며 기본적으로 콘솔에서 이 파일과 상호 작용할 수 없습니다. --show-child-io 스위치를 사용하여 stdinstdout과 상호 작용합니다.
  • Ctrl+C 또는 SIGTERM을 통해 도구를 종료하면 도구와 자식 프로세스가 모두 안전하게 종료됩니다.
  • 자식 프로세스가 도구보다 먼저 종료되면 도구도 종료되며 추적을 안전하게 볼 수 있습니다.

추적 보기

수집된 추적 파일은 Windows에서 PerfView의 이벤트 보기를 사용하여 볼 수 있습니다. 모든 어셈블리 로딩 이벤트에는 접두사 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에서 수집된 추적을 열고 이벤트 보기를 엽니다. 이벤트 목록을 Microsoft-Windows-DotNETRuntime/AssemblyLoader 이벤트로 필터링합니다.

PerfView assembly loader filter image

추적이 시작된 후 애플리케이션에서 발생한 모든 어셈블리 로드가 표시됩니다. 이 예제에 대한 원하는 어셈블리 로드 작업 MyLibrary를 검사하기 위해 몇 가지 추가 필터링을 수행할 수 있습니다.

어셈블리 로드

왼쪽에 있는 이벤트 목록을 사용하여 Microsoft-Windows-DotNETRuntime/AssemblyLoader 아래의 StartStop 이벤트로 보기를 필터링합니다. AssemblyName, ActivityIDSuccess 열을 보기에 추가합니다. MyLibrary를 포함하는 이벤트로 필터링합니다.

PerfView Start and Stop events image

이벤트 이름 AssemblyName ActivityID Success
AssemblyLoader/Start MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/
AssemblyLoader/Stop MyLibrary, Culture=neutral, PublicKeyToken=null //1/2/ False

Stop 이벤트에 하나의 Start/Stop 쌍과 Success=False가 표시되어 로드 작업이 실패했음을 나타냅니다. 두 이벤트의 활동 ID는 동일합니다. 활동 ID를 사용하여 다른 모든 어셈블리 로더 이벤트를 이 로드 작업에 해당하는 이벤트로만 필터링할 수 있습니다.

로드 시도 분석

로드 작업에 대한 자세한 분석을 보려면 왼쪽에 있는 이벤트 목록을 사용하여 Microsoft-Windows-DotNETRuntime/AssemblyLoader 아래의 ResolutionAttempted 이벤트로 보기를 필터링합니다. AssemblyName, StageResult 열을 보기에 추가합니다. 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에 대해 처리기를 호출하여 어셈블리를 확인하려고 했음을 나타냅니다. 이러한 모든 단계에 대해 어셈블리를 찾을 수 없습니다.

확장 지점

호출된 확장 지점을 확인하려면 왼쪽에 있는 이벤트 목록을 사용하여 Microsoft-Windows-DotNETRuntime/AssemblyLoader 아래의 AssemblyLoadContextResolvingHandlerInvokedAppDomainAssemblyResolveHandlerInvoked로 보기를 필터링합니다. AssemblyNameHandlerName 열을 보기에 추가합니다. 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

위의 이벤트는 AssemblyLoadContext.Resolving 이벤트에 대해 OnAssemblyLoadContextResolving이라는 처리기가 호출되고 AppDomain.AssemblyResolve 이벤트에 대해 OnAppDomainAssemblyResolve이라는 처리기가 호출되었음을 나타냅니다.

다른 추적 수집

AssemblyLoadContext.Resolving 이벤트에 대한 처리기가 MyLibrary 어셈블리를 로드하도록 인수를 사용하여 애플리케이션을 실행합니다.

AssemblyLoading /d default alc-resolving

위의 단계를 사용하여 다른 .nettrace 파일을 수집하고 엽니다.

다시 MyLibrary에 대한 StartStop 이벤트로 필터링합니다. Start/Stop 쌍과 그 사이에 또 다른 Start/Stop이 표시됩니다. 내부 로드 작업은 AssemblyLoadContext.LoadFromAssemblyPath을 호출했을 때 AssemblyLoadContext.Resolving에 대한 처리기를 통해 트리거된 로드를 나타냅니다. 이번에는 Stop 이벤트에 Success=True가 표시되어 로드 작업이 성공했음을 나타냅니다. ResultAssemblyPath 필드는 결과 어셈블리의 경로를 표시합니다.

PerfView successful Start and Stop events image

이벤트 이름 AssemblyName ActivityID Success 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 이벤트가 더 이상 없습니다.

참고 항목