다음을 통해 공유


WPF 렌더링 스레드 오류

이 문서에서는 예외가 발생하거나 애플리케이션이 중단되거나 NotifyPartitionIsZombie 중단되는 오류에 SyncFlush 특히 주의하여 WPF의 렌더링 스레드의 실패에 WaitForNextMessage SynchronizeChannel대해 설명합니다.

원래 제품 버전: .NET Framework 4.8

SyncFlush, WaitForNextMessage, SynchronizeChannel 및 NotifyPartitionIsZombie의 오류

개발자는 WPF(Windows Presentation Foundation) 애플리케이션을 사용하여 스레드 오류를 렌더링하는 데 문제가 발생하는 경우가 많습니다. 사용자는 다음과 같은 예외를 throw하는 애플리케이션을 보고할 수 있습니다.

  • System.Runtime.InteropServices.COMException: UCEERR_RENDERTHREADFAILURE(HRESULT에서 예외: 0x88980406)
  • System.InvalidOperationException: 렌더링 스레드에서 지정되지 않은 오류가 발생했습니다.
  • System.OutOfMemoryException: 프로그램 실행을 계속하기 위한 메모리가 부족합니다.

예외의 호출 스택이 시작되거나 NotifyPartitionIsZombie.에서 SyncFlush 시작됩니다. 예시:

   at System.Windows.Media.Composition.DUCE.Channel.SyncFlush()  
   at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable\`1 channelSet)  
   at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget)  
   at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam)  
   at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)  
   at System.Windows.Media.MediaContext.NotifyPartitionIsZombie(Int32 failureCode)  
   at System.Windows.Media.MediaContext.NotifyChannelMessage()  
   at System.Windows.Interop.HwndTarget.HandleMessage(Int32 msg, IntPtr wparam, IntPtr lparam)  

애플리케이션이 중단 WaitForNextMessage 되거나 SynchronizeChannel다음과 같은 호출 스택이 있을 수도 있습니다.

   ntdll.dll!NtWaitForMultipleObjects
   kernelbase.dll!WaitForMultipleObjectsEx
   kernelbase.dll!WaitForMultipleObjects
   wpfgfx_v0400.dll!CMilChannel::WaitForNextMessage
   wpfgfx_v0400.dll!MilComposition_WaitForNextMessage
   presentationcore.dll!System.Windows.Media.MediaContext.CompleteRender
   kernelbase.dll!WaitForSingleObject
   wpfgfx_v0400.dll!CMilConnection::SynchronizeChannel
   wpfgfx_v0400.dll!CMilChannel::SyncFlush
   presentationcore.dll!System.Windows.Media.Composition.DUCE+Channel.SyncFlush
   presentationcore.dll!System.Windows.Media.MediaContext.CompleteRender
   presentationcore.dll!System.Windows.Interop.HwndTarget.OnResize
   presentationcore.dll!System.Windows.Interop.HwndTarget.HandleMessage

렌더링 스레드에서 오류가 발생한 증상입니다. 수신된 예외 및 호출 스택이 일반적이므로 진단하기 어려운 문제입니다. 렌더링 스레드 오류는 근본 원인에 관계없이 위에 표시된 호출 스택 중 하나(또는 약간의 변형)를 생성합니다. 이렇게 하면 문제를 진단하거나 두 번의 충돌이나 중단이 동일한 근본 원인에서 비롯되는 경우를 인식할 수 있으며, 특히 어렵습니다.

WPF 렌더링 스레드 및 UI 스레드와 차이점에 대한 설명

각 WPF 애플리케이션에는 자체 메시지 펌프(Dispatcher.Run)를 실행하는 하나 이상의 UI 스레드가 있을 수 있습니다. 각 UI 스레드는 스레드의 메시지 큐에서 창 메시지를 처리하고 해당 스레드가 소유한 창으로 디스패치합니다. 각 WPF 애플리케이션에는 하나의 렌더링 스레드만 있습니다. DirectX/D3D(소프트웨어 렌더링 파이프라인을 사용하는 경우 및/또는 GDI)와 통신하는 별도의 스레드입니다. WPF 콘텐츠의 경우 각 UI 스레드는 그릴 내용에 대한 자세한 지침을 렌더링 스레드에 보냅니다. 그런 다음 렌더링 스레드는 이러한 지침을 받아 콘텐츠를 렌더링합니다.

위에서 언급한 오류의 원인

위에서 언급한 예외 및 중단은 심각한 오류가 발생한 WPF 렌더링 스레드의 결과로 UI 스레드에서 발생합니다. 이러한 오류에는 몇 가지 가능한 원인이 있지만 렌더링 스레드는 해당 정보를 UI 스레드와 공유하지 않습니다. 이러한 예외 및 중단은 단일 루트 버그 또는 문제에서 비롯된 것이 아니므로 특정 방법으로 해결할 수 없습니다.

WPF의 렌더링 스레드는 DirectX/D3D, User32 또는 GDI32와 같은 다른 구성 요소를 호출할 때 성공 또는 실패에 대한 반환 값을 확인합니다. 오류가 감지되면 WPF는 렌더링 파티션을 "좀비"하고 두 스레드가 동기화될 때 UI 스레드에 실패를 알립니다. 렌더링 스레드는 수신하는 오류를 적절한 관리되는 예외에 매핑하려고 시도합니다. 예를 들어 메모리 부족 조건으로 인해 WPF 렌더링 스레드가 실패한 경우 오류를 a System.OutOfMemoryException 에 매핑하고 UI 스레드에 표시되는 예외가 됩니다. 렌더링 스레드는 몇 위치의 UI 스레드와만 동기화되므로 일반적으로 위의 호출 스택은 실제로 발생한 위치가 아니라 문제를 확인할 수 있는 위치에 표시됩니다. 창의 설정이 업데이트되거나(크기, 위치 등) UI 스레드가 렌더링 스레드에서 "채널" 메시지를 처리하는 위치에서 가장 일반적으로 동기화됩니다.

기본적으로 UI 스레드의 예외 및 호출 스택은 문제를 진단하는 데 도움이 되지 않습니다. 이는 예외가 throw될 때까지 렌더링 스레드가 이미 실패 지점을 통과했기 때문입니다. 렌더링 스레드의 중요 상태는 오류가 발생한 위치와 이유를 이해하는 데 도움이 되지만 이미 손실되었습니다. 이렇게 하면 WPF 애플리케이션을 작성하는 사람이 오류가 발생한 이유 또는 이를 방지하는 방법을 알 수 없습니다. Microsoft의 경우 사후 사용자 덤프 파일에서 이 파일을 디버그하는 것이 약간 더 좋습니다. 렌더링 스레드는 실패한 호출 스택의 순환 버퍼를 유지합니다. 이 버퍼는 전용 디버거 확장 및 프라이빗 디버그 기호를 통해 내부적으로 다시 구성하여 대략적인 초기 실패 지점을 표시할 수 있습니다. 그러나 실패 시 로컬, 스택 변수 및 힙 개체와 같은 중요한 상태에 액세스할 수 없습니다. 일반적으로 애플리케이션을 다시 실행하여 관련된 것으로 의심되는 호출에서 오류를 찾습니다.

오류의 일반적인 원인

WPF 렌더링 스레드 오류의 가장 일반적인 버킷은 비디오 하드웨어 또는 드라이버 문제와 관련이 있습니다. WPF가 DirectX를 통해 비디오 드라이버에 기능을 쿼리할 때 드라이버가 해당 기능을 잘못 보고하여 WPF가 일부 DirectX/D3D 오류를 발생시키는 코드 경로를 사용할 수 있습니다. 드라이버가 기능을 잘못 보고하지 않지만 올바르게 구현되지 않은 경우도 있습니다. 대부분의 렌더링 스레드 오류는 WPF가 드라이버의 일부 결함을 노출하는 방식으로 하드웨어 렌더링 파이프라인을 활용하려고 시도하여 발생합니다. 이는 최신 그래픽 장치 및 드라이버가 있는 최신 버전의 Windows에서 발생할 수 있지만 WPF의 초기 버전만큼 일반적이지는 않습니다. 따라서 렌더링 스레드 오류를 테스트 및/또는 해결하기 위한 첫 번째 제안 중 하나는 WPF에서 하드웨어 가속을 사용하지 않도록 설정하는 것입니다.

드라이버(또는 DirectX)가 처리하기에 너무 복잡한 장면을 렌더링하도록 요청하는 앱에서 오류가 발생할 수도 있습니다. 이것은 최신 드라이버에서 일반적이지는 않지만 모든 장치에는 제한이 있으며 이를 초과하는 것은 불가능하지 않습니다.

렌더링 스레드 오류의 또 다른 기록 소스는 WPF에서 Window.AllowsTransparency 또는 Popup.AllowsTransparency 속성을 사용하여 계층화된 창을 사용하는 것입니다. 이전 버전의 Windows에는 계층화된 창에 문제가 있었지만 대부분 Windows Vista에서 DWM(데스크톱 창 관리자)이 도입되어 해결되었습니다.

렌더링 스레드 오류가 매니페스트되는 System.OutOfMemoryException경우 렌더링 스레드는 일부 리소스가 소진되는 프로세스의 희생자일 수 있습니다. 렌더링 스레드는 일부 리소스를 Win32/DX 할당하려고 했지만 실패한 API로 호출되었습니다. WPF 맵은 같은 E_OUTOFMEMORY 값을 반환하거나 ERROR_NOT_ENOUGH_MEMORYSystem.OutOfMemoryException반환합니다. 예외가 "메모리"를 참조하지만 실패는 GDI 개체 핸들, 다른 시스템 핸들, GPU 메모리, 일반 RAM 메모리 등과 같은 모든 종류의 리소스를 참조할 수 있습니다.

리소스 할당 실패에 대한 설명

두 가지 설명은 오류 및 리소스 할당 실패에 적용됩니다 System.OutOfMemoryException .

  • 근본 원인은 오류가 발생하는 코드에 있을 수 없습니다. 대신, 프로세스에 리소스를 과도하게 소비하는 다른 코드가 있을 수 있으며, 정상적으로 성공한 요청에 남아 있는 코드는 없습니다.

  • 요청이 비정상적으로 큰 경우 충분한 리소스가 있음에도 불구하고 오류가 발생할 수 있습니다. 많은 양의(연속된) 메모리에 대한 요청이 있는 경우 시스템에 충분한 메모리가 있는 경우에도 A System.OutOfMemoryException 가 발생할 수 있습니다. 다음은 실제 예제입니다. Visual Studio 플러그 인이 이전 세션에 저장된 상태에서 창을 복원할 준비를 하고 있었습니다. 이전 모니터와 현재 모니터 간의 DPI 차이에 대해 잘못 조정되었으며, 이는 여러 WPF, WindowsForms 및 VS 창 호스팅 구성 요소 계층의 조정으로 인해 창의 크기를 예상보다 16배 더 크게 설정했습니다. 렌더링 스레드는 필요한 것보다 256배 더 큰 백 버퍼를 할당하려고 했으나 예상 할당에 사용할 수 있는 메모리가 충분한 경우에도 실패했습니다.

일반 권장 사항

  1. 하드웨어 가속 사용 안 함 옵션설명된 DisableHWAcceleration 레지스트리 값을 사용하여 하드웨어 렌더링을 사용하지 않도록 설정합니다. 이는 컴퓨터의 모든 WPF 애플리케이션에 영향을 줍니다. 이 작업은 문제가 그래픽 하드웨어 또는 드라이버와 관련이 있는지 테스트하는 방법으로만 수행합니다. 이 경우 보다 세부적인 수준에서 하드웨어 가속을 프로그래밍 방식으로 사용하지 않도록 설정하여 문제를 해결할 수 있습니다. HwndTarget.RenderMode 속성을 사용하거나 RenderOptions.ProcessRenderMode 속성을 사용하여 프로세스별로 이 작업을 수행할 있습니다.

  2. 비디오 드라이버를 업데이트하거나 문제 컴퓨터에서 다른 비디오 하드웨어를 사용해 보세요.

  3. 대상 플랫폼에 사용할 수 있는 .NET의 최신 버전 및 서비스 팩 수준으로 업그레이드합니다.

  4. 최신 운영 체제로 업그레이드합니다.

  5. 애플리케이션의 사용 Windows.AllowsTransparencyPopup.AllowsTransparency 사용을 사용하지 않도록 설정합니다.

  6. 보고되는 경우 System.OutOfMemoryExceptions 성능 모니터 프로세스의 메모리 사용량, 특히 모든 힙 카운터의 Process\Virtual Bytes, Process\Private Bytes 및 .NET CLR Memory\# 바이트를 모니터링합니다. Windows 작업 관리자에서 프로세스에 대한 사용자 개체 및 GDI 개체도 모니터링합니다. 특정 리소스가 소진되는 것으로 확인되면 애플리케이션 문제를 해결하여 과도한 리소스 사용량을 해결합니다. 위의 두 가지 리소스 할당 문제에 대해 유의하세요.

  7. 여러 플랫폼 또는 다른 비디오 하드웨어/드라이버 조합에서 발생하는 재현 가능한 시나리오가 있는 경우 WPF 버그가 있을 수 있습니다. Microsoft에 문제를 보고하기 전에 조사를 허용하도록 충분한 정보를 수집해야 합니다. 호출 스택만으로는 충분하지 않습니다. Microsoft에는 다음과 같은 자세한 정보가 필요합니다.

    • 환경에 대한 설명(OS, .NET 및 그래픽)을 포함하여 문제를 재현하는 단계가 포함된 전체 VS 솔루션입니다.
    • 문제의 시간 이동 디버깅 추적입니다.
    • 전체 크래시 덤프입니다.