Michael Könings Blog

a generalist's specialties

November 2007 - Einträge

HowTo: .NET Winforms hängt ! Was tun ?

Manchmal kommt man mit den Bord-Mitteln von Visual Studio einfach nicht weiter: Die Applikation "hängt" , im angehängten Debugger ist nichts zu sehen, ausser der wohlbekannten Zeile:

static void Main()        {            Application.EnableVisualStyles();            Application.SetCompatibleTextRenderingDefault(false);            Application.Run(new Form1());

        }

 

Jetzt muss man mit "härteren" Mitteln ran: Vom MS Support Team gibt es ein Script, das einen MiniDump der "lebenden" Applikation erstellt. Test User können diese Dumps bei Bedarf leicht selbst erstellen (.BAT File).

Als Output bekommt man pro Dump ein Verzeichnis mit Log Dateien, dem eigentlichen Mini-Dump, sowie einigen Umgebungsinformantionen, z.B. welche Prozesse sonst noch gerade liefen, etc.

Was macht man jetzt mit so einem Dump ?

Es gibt Tools, die diese Dumps laden und interpretieren können. Ich konnte die Dumps z.B. mit .NET Memory Profiler anschauen, ein sehr empfehlenswertes Werkzeug, wenn man auf der Suche nach Memory Problemen ist (darüber sollte ich auch noch bloggen...). Jedoch kann dieses Tool nicht den aktuellen Callstack anzeigen, genau das ist es jedoch, was wir bräuchten.

Echte Geeks nehmen aber was anderes: die Microsoft Debbuging Tools for Windows . Einfach runterladen und installieren...und...

Wow. Jede Menge Command-line Tools. Und jetzt ?

Ahh, es ist doch ein Windows Tool dabei: Windbg.exe

Damit kann man Einiges tun, (wenn man sich damit auskennt). Der Laie (ja, dazu zähle ich jetzt auch mal :-) ) steht erst mal mit offenem Mund davor und versteht nichts.  Nach einigem Googeln habe ich folgendes herausgefunden:

1. Du brauchst Symbols (PDB files) um die Funktionsnamen der System DLLs in den  Callstacks vernünftig anzeigen zu können, sonst bekommst du nur Speicheradressen. Diese gibt es live und täglich frisch von Microsoft, man kann sie entweder komplett runterladen oder in WinDbg nur die Url sowie ein lokales Cache Verzeichnis angeben:

Url to Symbol Files

Die benötigten PDB files werden so im Hintergrund automatisch heruntergeladen.

jetzt kannst Du im "Processes and Threads" Fenster zwischen den Threads wechseln und siehst einen (eingermassen) verständlichen Callstack dazu im callstack- Fenster.

Jedoch werden Befehle aus den Managed DLLS immer noch nicht schön angezeigt...

Dazu brauchen wir noch

2. den Zauberbefehl: !analyze -v  Dieser zeigt uns die im Dump versteckten Informationen zur Exception relativ übersichtlich und verständlich an (siehe unterer Teil im Bild).

Jetzt haben wir auch für die Managed DLLs einen Callstack der Exception.

winDbg

Jetzt noch ein bisschen googeln....

Und Volltreffer: OnUserPreferencesChanged ist unser Problem. Windows schickt Messages an alle existierenden Fenster, wenn sich etwas Grundlegendes am Desktop ändert, z.B. Änderungen der Fensterfarben etc.. Dieser Event feuert auch, wenn der Desktop in den Screensaver oder Lock-Modus geht. Alle Winforms Fenster abonnieren sich automatisch auf diesen Event. Fenster, die schon disposed aber noch nicht vom Garbage collector aufgeräumt sind, "hängen" in einem Zustand der Probleme machen kann. Ganz schlimm wird es, wenn diese Fenster/Control von einem Workerthread erzeugt wurden....

Das war unser Problem, hätte man aber wissen können :-).

Aber wie bekommt man heraus, welches Fenster das Problem verursacht, wenn es unsichtbar ist ?

Dazu gibt es das Tool Winspector. Dieses zeigt sehr übersichtlich live die Aktivitäten der Fenster für alle Prozesse an. Sehr cool. Die "bösen" Fenster hat man so schnell gefunden.

image

Lesson learned: Keine UI Objekte auf Worker-Threads erzeugen!