Fixierte Instanzen für GC - Nicht von meinem verwalteten Code aus nachvollziehbar

9

So verwende ich WPF 3.5 mit MVVM + DataTemplate-Methode, um zwei Ansichten auf der GUI zu laden. Ich habe während der Speicherprofilerstellung festgestellt, dass Elemente, die als Teil eines Elementcontainers mit Elementsteuerelementen generiert wurden, in den Speicher gesteckt werden und GCed selbst nach dem Entladen der Ansicht nicht erhalten werden!

Ich habe gerade Tests durchgeführt und festgestellt, dass es selbst für den einfachsten Code reproduzierbar ist ... Ihr könnt es selbst überprüfen.

XAML:

%Vor%

Code dahinter:

%Vor%

Ich führe erzwungene GC durch Linke Umschalttaste + Alt + Strg + G. Alle Elemente für die Test1 oder Test3 -Ansicht und Ansichtsmodell werden tot, nachdem sie korrekt entladen wurden. Das ist also wie erwartet.

Aber die Sammlung, die im Test1 -Modell generiert wurde (das Test2 -Objekte hat), bleibt im Speicher verankert. Und es zeigt an, dass das Array das ist, das vom Elementcontainer der Listbox verwendet wird, da es die Anzahl der de-virtualisierten Elemente aus der Listbox anzeigt! Dieses gepinnte Array ändert seine Größe, wenn wir die Ansicht in Test1 view mode minimieren oder wiederherstellen! Einmal waren es 16 Artikel und beim nächsten Mal waren es 69 Artikel beim Profilieren.

Das bedeutet, dass WPF das Pinning von Elementen durchführt, die in Elementsteuerelementen generiert wurden! Kann das jemand erklären? Hat das einen erheblichen Nachteil?

Vielen Dank.

    
WPF-it 21.02.2012, 13:10
quelle

2 Antworten

3

Das Problem wird dadurch verursacht, dass der Bindungsmechanismus die Listenelemente, die tatsächlich zur Anzeige auf dem Bildschirm bestimmt waren, nicht vollständig freigegeben hat. Das letzte Bit ist fast sicher, warum Sie unterschiedliche Anzahl von "verwaisten" Instanzen in verschiedenen Läufen sehen. Je mehr Sie in der Liste blättern, desto mehr Probleme erzeugen Sie.

Dies scheint mit der gleichen Art von zugrunde liegendem Problem zu tun zu haben, wie in ein Fehlerbericht, den ich vor über einem Jahr eingereicht habe , da die Pinning-Root- und gepinnten Instanzenbäume ähnlich sind. (Um diese Art von Details in einem praktischen Format zu sehen, möchten Sie vielleicht eine Kopie eines etwas schickeren Speicherprofilers wie ANTS Speicher Profiler .)

Die wirklich schlechte Nachricht ist, dass Ihre verwaisten Instanzen nach dem Ende des Fensters selbst festgenagelt werden, also können Sie sie wahrscheinlich nicht ohne den gleichen Hack säubern, den ich im WinForms-Szenario verwenden musste, um von den verbindlichen Privaten.

Die einzige gute Nachricht in diesem Zusammenhang ist, dass das Problem nicht auftritt, wenn Sie die Bindung an verschachtelte Eigenschaften vermeiden können. Wenn Sie beispielsweise Test2 eine Überschreibung ToString () hinzufügen, um den Wert seiner B-Eigenschaft zurückzugeben und DisplayMemberPath aus Ihrem Listenfeldelement zu entfernen, wird das Problem verschwinden. z.B.:

%Vor% %Vor%     
Nicole Calinoiu 24.02.2012, 20:19
quelle
0

In Ihrem Beispielcode oben sehe ich nicht, wo Sie irgendwelche der Bilder entladen?

Aber vorausgesetzt, dass Sie die gesamte Ansicht entladen, ist dies immer noch vorhersehbar. Der Faktor, den Sie nicht berücksichtigen, ist der Dispatcher. Der Dispatcher ist eine priorisierte Ereigniswarteschlange und verwaltet für jeden Delegaten in dieser Warteschlange einen Verweis auf die Objekte, auf die diese Delegierten verweisen. Das bedeutet, dass es sehr wahrscheinlich ist, dass sich etwas in Ihrer Ansicht nach einem Unloaded-Ereignis in der Warteschlange befindet und daher eine legitime Referenz im GC hat. Sie können GC.Collect, bis Sie blau im Gesicht sind und es wird nie Objekte mit verbleibenden Referenzen sammeln.

Sie müssen also den Dispatcher pumpen und dann GC.Collect aufrufen. Etwas wie das:

%Vor%

Eine weitere wirklich häufige Ursache für Speicherlecks in .net hat damit zu tun, dass Ereignisse angehängt und nicht korrekt aufgehoben werden. Ich sehe nicht, dass Sie dies in Ihrem Beispiel oben tun, aber wenn Sie Ereignisse anhängen, stellen Sie sicher, dass Sie sie in Unloaded oder Dispose lösen oder wo immer es am besten ist.

    
justin.m.chase 23.02.2012 18:04
quelle