Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo illustra gli errori nel thread di rendering di Windows Presentation Foundation (WPF). Questo articolo è incentrato sulle eccezioni che si verificano in SyncFlush o NotifyPartitionIsZombie e situazioni di blocco che si verificano in WaitForNextMessage o SynchronizeChannel.
Le applicazioni WPF possono avere uno o più thread dell'interfaccia utente che eseguono il proprio message pump (Dispatcher.Run). Ogni thread dell'interfaccia utente è responsabile dell'elaborazione dei messaggi della finestra dalla coda dei messaggi del thread e dell'invio alle finestre gestite dal thread. Ogni applicazione WPF ha un solo thread di rendering. Il thread separato comunica con Microsoft DirectX D3D (o GDI, se si utilizza la pipeline di rendering software). Per il contenuto WPF, ogni thread dell'interfaccia utente invia istruzioni dettagliate al thread di rendering su cosa disegnare. Il thread di rendering segue quindi queste istruzioni per eseguire il rendering del contenuto.
Si applica a: .NET Framework 4.8
Errori in SyncFlush, WaitForNextMessage, SynchronizeChannel e NotifyPartitionIsZombie
Gli sviluppatori spesso riscontrano problemi correlati a errori del thread di rendering che si verificano nelle applicazioni WPF. Gli utenti potrebbero segnalare che l'applicazione genera un'eccezione, ad esempio:
- System.Runtime.InteropServices.COMException: UCEERR_RENDERTHREADFAILURE (eccezione da HRESULT: 0x88980406)
- System.InvalidOperationException: si è verificato un errore non specificato nel thread di rendering.
- System.OutOfMemoryException: memoria insufficiente per continuare l'esecuzione del programma.
Lo stack di chiamate correlato inizia da SyncFlush o NotifyPartitionIsZombie. Ad esempio:
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)
L'applicazione potrebbe smettere di rispondere in WaitForNextMessage o SynchronizeChannel e generare uno stack di chiamate, ad esempio:
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
Questi stack di chiamate sono sintomi di un errore nel thread di rendering. Si tratta di un problema complesso da diagnosticare perché le eccezioni e gli stack di chiamate sono generici. Gli errori del thread di rendering generano uno degli stack di chiamate elencati qui (o una variazione minore degli stack di chiamate) indipendentemente dalla causa principale. Pertanto, può essere difficile diagnosticare il problema o riconoscere una situazione in cui eventi imprevisti separati di non risposta hanno la stessa causa radice.
Cause degli errori in SyncFlush, WaitForNextMessage, SynchronizeChannel e NotifyPartitionIsZombie
Le eccezioni e le situazioni in cui il software smette di rispondere si verificano in un thread dell'interfaccia utente se il thread di rendering WPF riscontra un errore irreversibile. Questi errori hanno diverse possibili cause, ma il thread di rendering non condivide tali informazioni insieme al thread dell'interfaccia utente. Poiché questi errori non sono correlati a un singolo bug o problema radice, non hanno una soluzione specifica.
Il thread di rendering di WPF controlla il valore restituito per esito positivo o negativo quando effettua una chiamata a un altro componente, ad esempio DirectX D3D, User32 o GDI32. Quando viene rilevato un errore, WPF segna come inattiva la partizione di rendering e comunica al thread dell'interfaccia utente dell'errore quando i due thread vengono sincronizzati. Il thread di rendering tenta di mappare l'errore ricevuto a un'eccezione gestita appropriata. Ad esempio, se il thread di rendering WPF non è riuscito a causa di una condizione di memoria insufficiente, esegue il mapping dell'errore a un oggetto System.OutOfMemoryException. Tale eccezione viene visualizzata nel thread dell'interfaccia utente. Il thread di rendering viene sincronizzato con il thread dell'interfaccia utente in poche posizioni. Di conseguenza, gli stack di chiamate menzionati nella sezione precedente in genere appaiono dove si notano sintomi del problema, non dove si verifica effettivamente il problema. La sincronizzazione si verifica in genere nei percorsi in cui le impostazioni di una finestra vengono aggiornate (dimensioni, posizione e così via) o in cui il thread dell'interfaccia utente gestisce un messaggio "canale" dal thread di rendering.
Per impostazione predefinita, le eccezioni e gli stack di chiamate nel thread dell'interfaccia utente non sono risorse utili per diagnosticare il problema. Nel momento in cui l'eccezione viene lanciata, il thread di rendering ha già oltrepassato il punto di fallimento. Lo stato critico del thread di rendering aiuterebbe a comprendere dove e perché si è verificato l'errore, ma è già andato perso. A causa di questa situazione, l'autore di un'applicazione WPF non può sapere perché si è verificato l'errore o come evitarlo. Anziché analizzare le eccezioni e gli stack di chiamate, viene eseguito il debug del problema in un file di dump dell'utente postmortem. Anche se questo metodo è solo leggermente più utile, il thread di rendering mantiene un buffer circolare dello stack di chiamate con errori. È possibile ricostruire il buffer internamente usando un'estensione del debugger proprietaria e simboli di debug privati per mostrare il punto iniziale approssimativo di errore. Tuttavia, non è possibile accedere allo stato critico, ad esempio variabili locali, variabili dello stack e oggetti heap al momento dell'errore. L'applicazione viene in genere eseguita di nuovo per cercare errori nelle chiamate che si sospetta siano coinvolte.
Guasti dell'hardware video o dei driver video
Il bucket più comune di errori del thread di rendering WPF è associato a problemi di hardware o driver video. Quando WPF esegue una query sul driver video per individuare le funzionalità tramite DirectX, il driver potrebbe indicare erroneamente le relative funzionalità. Questa azione induce WPF a seguire un percorso di codice che provoca alcuni errori di DirectX D3D. Il driver potrebbe anche essere implementato in modo non corretto. La maggior parte degli errori del thread di rendering si verifica perché WPF tenta di usare la pipeline di rendering hardware in modo da esporre alcuni difetti nel driver. Questa condizione può verificarsi nelle versioni moderne di Windows che usano dispositivi grafici e driver moderni, anche se non così comunemente come avveniva nei primi giorni di WPF. Per questo motivo, quando si inizia a testare o risolvere un errore del thread di rendering, è consigliabile disabilitare prima l'accelerazione hardware in WPF.
Un errore può verificarsi anche se un'app richiede il rendering di una scena troppo complessa per il rendering del driver (o DirectX). Questa situazione non è comune per i driver moderni. Tuttavia, ogni dispositivo ha limiti che possono essere superati.
Un'altra origine cronologica degli errori dei thread di rendering sono le proprietà Window.AllowsTransparency o Popup.AllowsTransparency in WPF. Queste proprietà causano l'uso di finestre a più livelli . Le finestre a più livelli hanno causato problemi nelle versioni precedenti di Windows. Tuttavia, la maggior parte di questi problemi è stata risolta dall'introduzione di Desktop Window Manager (DWM) in Windows Vista.
Se un errore del thread di rendering si manifesta come , System.OutOfMemoryExceptiontale errore indica in genere che il processo ha esaurito alcune risorse. In questa situazione, il thread di rendering ha chiamato un'API di Win32/DX che ha tentato senza successo di allocare una risorsa. Le mappe WPF restituiscono valori come E_OUTOFMEMORY o ERROR_NOT_ENOUGH_MEMORY a un oggetto System.OutOfMemoryException. Anche se la voce di eccezione fa riferimento a "memoria", questa menzione può fare riferimento a qualsiasi tipo di risorsa, ad esempio handle di oggetti GDI, altri handle di sistema, memoria GPU, memoria RAM standard e così via.
Osservazioni sugli errori di allocazione delle risorse
Le osservazioni seguenti si applicano ai System.OutOfMemoryException fallimenti e a qualsiasi errore di allocazione delle risorse.
La causa radice potrebbe non essere correlata al codice che riscontra l'errore. All'interno del processo, altro codice può utilizzare eccessivamente la risorsa e non lasciare risorse per segmenti di codice che altrimenti verrebbero eseguiti correttamente.
Se la richiesta è insolitamente grande, l'errore potrebbe verificarsi nonostante una risorsa che sembra essere abbondante. Una richiesta di grande quantità di memoria contigua potrebbe causare un
System.OutOfMemoryExceptionanche se il sistema dispone di molta memoria. Ecco un esempio reale: un componente aggiuntivo di Visual Studio prepara il ripristino della finestra da uno stato salvato in una sessione precedente. Il componente aggiuntivo viene modificato in modo errato per la differenza in DPI tra i monitor precedenti e correnti. Poiché questo errore è composto da rettifiche da diversi livelli di componenti WPF, WindowsForms e componenti per l'hosting di finestre di Visual Studio, il componente aggiuntivo imposta le dimensioni della finestra su 16 volte la dimensione corretta. Il thread di rendering tenta quindi di allocare un back-buffer che è 256 volte superiore al necessario. Di conseguenza, il processo ha esito negativo anche se è disponibile memoria sufficiente per l'allocazione prevista.
Raccomandazioni generali
Disabilitare il rendering hardware. Usare il valore del Registro di sistema DisableHWAcceleration descritto in Opzione 'Disabilita Accelerazione Hardware'. Questa azione influisce su tutte le applicazioni WPF nel computer. Eseguire questo passaggio solo per verificare se il problema è correlato all'hardware o ai driver grafici. In caso affermativo, è possibile risolvere il problema disabilitando a livello di codice l'accelerazione hardware a un livello più granulare. Questo passaggio può essere eseguito per ogni finestra usando la proprietà HwndTarget.RenderMode o per ogni processo usando la proprietà RenderOptions.ProcessRenderMode .
Aggiornare i driver video o provare hardware video diverso nei computer con problemi.
Eseguire l'aggiornamento alla versione più recente e al livello di Service Pack di Microsoft .NET Framework disponibile per la piattaforma di destinazione.
Eseguire l'aggiornamento al sistema operativo più recente.
Disabilitare la possibilità di usare
Windows.AllowsTransparencyePopup.AllowsTransparencynell'applicazione.Se
System.OutOfMemoryExceptionsvengono rilevati, monitorare l'uso della memoria del processo in Performance Monitor. In particolare, monitorare i contatori Process\Virtual Bytes, Process\Private Bytes e .NET CLR Memory\# Bytes in tutti i contatori heap. Monitorare anche gli oggetti utente e gli oggetti GDI per il processo in Gestione attività di Windows. Se si determina che una risorsa specifica viene esaurita, risolvere i problemi dell'applicazione per correggere l'eccessivo consumo di risorse. Come linea guida, seguire le due osservazioni della sezione precedente sui problemi di allocazione delle risorse.Se si dispone di uno scenario riproducibile che si verifica su più piattaforme o in diverse combinazioni di hardware o driver video, è possibile che si verifichi un bug WPF. Assicurarsi di raccogliere informazioni sufficienti per abilitare un'indagine prima di segnalare il problema a Microsoft. Una pila delle chiamate da sola non è sufficiente. Sono necessarie informazioni più dettagliate, ad esempio:
- Soluzione Completa di Visual Studio che include i passaggi per riprodurre il problema, inclusa una descrizione dell'ambiente (sistema operativo, .NET e grafica).
- Traccia del debug di viaggi temporali del problema.
- Un file di dump completo per arresto anomalo.