Dela via


WPF-återgivningstrådsfel

Det här dokumentet beskriver fel i WPF:s återgivningstråd, med särskild uppmärksamhet på dem som orsakar ett undantag i SyncFlush eller som gör att program låser sig eller SynchronizeChannelWaitForNextMessage .NotifyPartitionIsZombie

Ursprunglig produktversion: .NET Framework 4.8

Fel i SyncFlush, WaitForNextMessage, SyncChannel och NotifyPartitionIsZombie

Utvecklare stöter ofta på problem som rör återgivning av trådfel med Windows Presentation Foundation-program (WPF). Användare kan rapportera att deras program genererar undantag, till exempel:

  • System.Runtime.InteropServices.COMException: UCEERR_RENDERTHREADFAILURE (undantag från HRESULT: 0x88980406)
  • System.InvalidOperationException: Ett ospecificerat fel uppstod i återgivningstråden.
  • System.OutOfMemoryException: Otillräckligt minne för att fortsätta körningen av programmet.

Undantagets anropsstack startar vid SyncFlush eller NotifyPartitionIsZombie. Till exempel:

   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)  

Programmet kan också hänga i WaitForNextMessage eller SynchronizeChannel, med en anropsstack som:

   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

Det här är symtom på ett fel i återgivningstråden. Det här är ett svårt problem att diagnostisera eftersom de undantag och anropsstackar som tas emot är generiska. Återgivningstrådsfel genererar en av anropsstackarna som visas ovan (eller en mindre variant av dem) oavsett rotorsaken. Detta gör det särskilt svårt att diagnostisera problemet, eller till och med känna igen när två krascher eller hängningar härrör från samma rotorsak.

Beskrivning av WPF-återgivningstråden och hur den skiljer sig från användargränssnittstråden

Varje WPF-program kan ha en eller flera UI-trådar som kör sin egen meddelandepump (Dispatcher.Run). Varje användargränssnittstråd ansvarar för att bearbeta fönstermeddelanden från trådens meddelandekö och skicka dem till fönster som ägs av den tråden. Varje WPF-program har bara en återgivningstråd. Det är en separat tråd som kommunicerar med DirectX/D3D (och/eller GDI om pipelinen för programvarurendering används). För WPF-innehåll skickar varje UI-tråd detaljerade instruktioner till återgivningstråden om vad som ska ritas. Återgivningstråden tar sedan dessa instruktioner och renderar innehållet.

Orsaker till de fel som nämns ovan

Undantagen och låsningarna som nämns ovan inträffar i en UI-tråd till följd av att WPF-återgivningstråden stöter på ett allvarligt fel. Det finns flera möjliga orsaker till dessa fel, men återgivningstråden delar inte den informationen med användargränssnittstråden. Eftersom dessa undantag och hängningar inte härrör från en enda rotbugg eller ett problem finns det inget specifikt sätt att åtgärda dem.

WPF:s återgivningstråd kontrollerar returvärdet för att lyckas eller misslyckas när den gör ett anrop till en annan komponent, till exempel DirectX/D3D, User32 eller GDI32. När ett fel upptäcks "zombies" wpf återgivningspartitionen och meddelar UI-tråden om felet när de två trådarna synkroniseras. Återgivningstråden försöker mappa felet som den tar emot till ett lämpligt hanterat undantag. Om WPF-återgivningstråden till exempel misslyckades på grund av ett minnesfel mappar den felet till en System.OutOfMemoryException och det är undantaget som visas i användargränssnittstråden. Återgivningstråden synkroniseras bara med användargränssnittstråden på några få platser, så anropsstackarna ovan visas vanligtvis där du märker problemet, inte där det faktiskt inträffade. De synkroniseras oftast på platser där ett fönsters inställningar uppdateras (storlek, position osv.) eller där användargränssnittstråden hanterar ett "kanalmeddelande" från återgivningstråden.

Undantag och anropsstackar i användargränssnittstråden är avsiktligt inte användbara för att diagnostisera problemet. Det beror på att när undantaget utlöses har återgivningstråden redan passerat felpunkten. Återgivningstrådens kritiska tillstånd skulle hjälpa oss att förstå var och varför felet inträffade, men det har redan gått förlorat. Detta gör det praktiskt taget omöjligt för någon som skriver ett WPF-program att veta varför felet inträffade eller hur man undviker det. För Microsoft är det bara något bättre att felsöka detta i en postmortem-användardumpfil. Återgivningstråden behåller en cirkulär buffert av den misslyckade anropsstacken, som vi kan rekonstruera internt med hjälp av ett egenutvecklat felsökningstillägg och privata felsökningssymboler för att visa den ungefärliga startpunkten för fel. Vi har dock inte åtkomst till det kritiska tillståndet, till exempel lokalbefolkningen, stackvariabler och heap-objekt vid tidpunkten för felet. Vi kör vanligtvis programmet igen för att leta efter fel på de anrop som vi misstänker är inblandade.

Vanliga orsaker till felen

Den vanligaste bucketen med WPF-återgivningstrådsfel är associerad med problem med videomaskinvara eller drivrutin. När WPF frågar videodrivrutinen om funktioner via DirectX kan drivrutinen rapportera sina funktioner felaktigt, vilket gör att WPF tar en kodsökväg som orsakar vissa DirectX/D3D-fel. Ibland rapporterar drivrutinen inte sina funktioner, men den har inte implementerats korrekt. De flesta fel i återgivningstråden orsakas av att WPF försöker använda pipelinen för maskinvarurendering på ett sätt som gör att drivrutinen är bristfällig. Detta kan inträffa på moderna versioner av Windows med moderna grafikenheter och drivrutiner, även om det inte är lika vanligt som det var i wpf:s tidiga dagar. Det är därför ett av våra första förslag för att testa och/eller kringgå ett återgivningstrådsfel är att inaktivera maskinvaruacceleration i WPF.

Det är också möjligt att ett fel orsakas av en app som ber om att återge en scen som är för komplex för drivrutinen (eller DirectX) att hantera. Detta är inte vanligt med moderna drivrutiner, men varje enhet har gränser och det är inte omöjligt att överskrida dem.

En annan historisk källa till återgivningstrådsfel är användningen av egenskaperna Window.AllowsTransparency eller Popup.AllowsTransparency i WPF, vilket gör att flerskiktade fönster används. Äldre versioner av Windows hade problem med skiktade fönster, men de flesta av dem har åtgärdats med introduktionen av Desktop Window Manager (DWM) i Windows Vista.

Om ett återgivningstrådsfel manifesteras som en System.OutOfMemoryException, var återgivningstråden förmodligen ett offer för processens uttömning av någon resurs. Återgivningstråden anropades till ett Win32/DX API som försökte allokera vissa resurser, men misslyckades. WPF mappar returvärden som E_OUTOFMEMORY eller ERROR_NOT_ENOUGH_MEMORY till en System.OutOfMemoryException. Även om undantaget refererar till "minne" kan felet referera till alla typer av resurser, till exempel GDI-objektreferenser, andra systemreferenser, GPU-minne, normalt RAM-minne osv.

Kommentarer om resursallokeringsfel

Två kommentarer gäller för System.OutOfMemoryException fel och eventuella resursallokeringsfel.

  • Rotorsaken kanske inte ligger i koden som påträffar felet. I stället kan det finnas annan kod i processen som överanvändningar resursen, vilket lämnar ingen kvar för en normalt lyckad begäran.

  • Om begäran är ovanligt stor kan felet inträffa trots en resurs som verkar riklig. En System.OutOfMemoryException kan inträffa även när systemet har gott om minne, om det finns en begäran om en stor mängd (sammanhängande) minne. Här är ett verkligt exempel: Ett Visual Studio-plugin-program förberedde sig för att återställa fönstret från ett tillstånd som sparades i en tidigare session. Den justerades felaktigt för skillnaden i DPI mellan de tidigare och aktuella övervakarna, vilket förvärrades med justeringar från flera lager av WPF-, WindowsForms- och VS-fönstervärdkomponenter för att ange fönstrets storlek 16 gånger större än det borde ha varit. Återgivningstråden försökte allokera en backbuffert som var 256 gånger större än vad som behövdes och misslyckades trots att det fanns mer än tillräckligt med minne tillgängligt för den förväntade allokeringen.

Allmänna rekommendationer

  1. Inaktivera maskinvarurendering med registervärdet DisableHWAcceleration som beskrivs i alternativet Inaktivera maskinvaruacceleration. Detta påverkar alla WPF-program på datorn. gör detta endast som ett sätt att testa om problemet är relaterat till grafikmaskinvara eller drivrutiner. I så fall kan du kringgå problemet genom att programmatiskt inaktivera maskinvaruacceleration på en mer detaljerad nivå. Detta kan göras per fönster med hjälp av egenskapen HwndTarget.RenderMode eller per process med hjälp av egenskapen RenderOptions.ProcessRenderMode .

  2. Uppdatera dina videodrivrutiner och/eller prova annan videomaskinvara på problemdatorerna.

  3. Uppgradera till den senaste versionen och service pack-nivån för den .NET som är tillgänglig för målplattformen.

  4. Uppgradera till det senaste operativsystemet.

  5. Inaktivera användningen av Windows.AllowsTransparency och Popup.AllowsTransparency i ditt program.

  6. Om System.OutOfMemoryExceptions rapporteras övervakar du processens minnesanvändning i Prestandaövervakaren, särskilt Process\Virtual Bytes, Process\Private Bytes och .NET CLR Memory\# Bytes i Alla Heaps-räknare. Övervaka användarobjekt och GDI-objekt för processen även i Windows Aktivitetshanteraren. Om du bedömer att en specifik resurs är slut kan du felsöka programmet för att åtgärda den överdrivna resursförbrukningen. Tänk på de två anmärkningarna ovan om resursallokeringsproblem.

  7. Om du har ett reproducerbart scenario som inträffar mellan plattformar eller på olika kombinationer av videomaskinvara/drivrutiner kan du ha en WPF-bugg. Se till att samla in tillräckligt med information för att tillåta undersökning innan du rapporterar problemet till Microsoft. Det räcker inte med en anropsstack. Microsoft behöver mer detaljerad information, till exempel:

    • En fullständig VS-lösning med steg för att återskapa problemet, inklusive beskrivning av miljön – OPERATIVSYSTEM, .NET och grafik.
    • En felsökningsspårning för tidsresor för problemet.
    • En fullständig kraschdump.