2010-09-30 4 views
7

Wir haben eine WPF-Anwendung, basierend auf Unity mit MMVVVM Muster. Im Anwendungslebenszyklus kann es mehrere Projektlebenszyklen geben, nach jedem Projektlebenszyklus führen wir einen manuellen Abbau durch und versuchen, alle Referenzen von ViewModels freizugeben. Für Ereignisabonnements mit Unity verwenden wir schwache Referenzen. Wir gehen also davon aus, dass wir nach dem Abbau GC Collect aufrufen können, so dass alle Müllobjekte Müll gesammelt werden. Wir haben eine andere Möglichkeit, alle Ereignisse manuell abzubestellen, aber wir bevorzugen die Garbage-Collection, da sie für uns ca. 200 MB entfernt, was das Laden neuer Projekte erleichtert.Unter welchen Umständen müssen wir GC.Collect zweimal anrufen

Mit einer Instanz beobachten wir, dass, wenn ich GC.Collect nur einmal aufrufen, seine Referenz noch für einige Zeit im Speicher verbleibt.

Aber wenn ich versuche, GC zweimal in Folge aufzurufen, räumt es alles schön auf.

GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 

Alle Gedanken oder Hinweise werden sehr geschätzt.

Update:

Es sind keine Finalizer der Klasse definiert.

Jetzt betrachte ich auch einen Fall, in dem dieses Objekt in einem anderen Objekt verwiesen wird, das einen Finalizer haben könnte. In unserem Framework haben wir Finalizer nur für DBProvider, also denke ich nicht, auch das ist der Fall.

+5

Was ist MMVVVM? Die römische Art zu codieren? – DanDan

+0

MVVM ist in WPF üblich, aber in unserem Fall haben wir verschiedene Anwendungen in verschiedenen .NET-Technologien und sie alle basieren auf dem üblichen DomainObject-Framework. Daher entschieden wir uns für eine neue Layer MV über unsere DomainObjects, um unsere WPF-Anwendungen zu vereinfachen. –

+0

MMVVVM = 2985, denke ich. –

Antwort

9

Klingt so, als hätten Sie etwas mit einem Finalizer. Wenn Sie nur einmal GC.Collect() aufrufen, werden die Finalisierer fertig gestellt, aber die finalisierten Objekte werden nicht gesammelt.

Ob dies ein Fehler ist oder nicht, ist eine andere Sache. Im Allgemeinen ist es keine gute Idee, Finalizer zu verwenden, die tatsächlich ausgeführt werden müssen, aber vielleicht ist es in Ihrem Fall in Ordnung.

+0

Ich überprüft mit dieser bestimmten Klasse, soweit ich sehen kann, gibt es keine Finalizer. –

+0

Nun betrachte ich einen Fall, in dem dieses Objekt in einem anderen Objekt referenziert wird, das einen Finalizer haben könnte. –

+0

Wenn ein Objekt einen Finalizer hat, werden alle Objekte, auf die es direkt oder indirekt verweist, den nächsten GC zumindest teilweise überleben (Finalizer, falls vorhanden, laufen auf solchen Objekten; WeakReferences können überleben, aber ich würde ihnen nicht vertrauen wird immer). – supercat

6

Wenn ich GC.Collect nur einmal aufrufen, bleibt seine Referenz für einige Zeit im Speicher.

Nicht wirklich seltsam. Wenn ein Objekt über einen Finalizer verfügt (und kein GC.SuppressFinalize() aufgerufen wurde), wird eine Ausführung ausgeführt (es wird nicht erfasst, sodass der Finalizer mit gültigen Objekten ausgeführt werden kann). Alle Instanzen, auf die dieses Objekt verweist, erhalten auch eine Ausführung. Eine zweite Runde durch den GC wird benötigt, um alles zu säubern.

Auf der anderen Seite sollten die meisten Programme, einschließlich großer und komplexer, ausgeführt werden können, ohne GC.Collect() einmal aufzurufen. Und Sie wollen zweimal nennen ...

nach jedem Zyklus Projektlebens wir ein manuellen tun Tear Down

Klingt kompliziert und leicht zu vermeiden ... Wie viele refernces geben es in Ihre Domain/Modelle anzeigen? Im Idealfall würden Sie einfach 1 oder 2 Referenzen auf ein "Haupt" -Objekt abschneiden und es vergessen.

+0

Tatsächlich befinden sich ganze Projektobjekte im Speicher, einschließlich V VM MV und M für den Projektlebenszyklus, also entschieden wir uns für einen manuellen Riss Ich denke auch über den von Ihnen erwähnten Fall, bitte sehen Sie Kommentare zu Jon Skeet Antwort –

+0

Ich sehe immer noch nicht die Notwendigkeit für eine manuelle Abriß, aber es wird komplex sein und Sie müssen nur einen kleinen ref .. . –

0

@Nitin, ich bin mir nicht sicher, ob mein Vorschlag Ihnen helfen würde oder nicht, aber als Faustregel sollten wir vermeiden, GC.Collect() explizit aufzurufen. weil es wahrscheinlich Leistungsproblem verursachen wird.Versuchen Sie stattdessen, dem richtigen Entsorgungsmuster zu folgen.

0

Sie haben eine schwache Referenz, von der Sie erwarten, dass sie auf null gesetzt ist, wenn Sie GC aufrufen, und Sie glauben, dass nichts das Objekt am Leben erhält.

Ich weiß nicht, wie schwach Referenzen in .net implementiert sind, aber es ist sehr möglich, dass sie die Sammlung von Objekten verzögern und ein System wie Finalizer verwendet.

Oder es könnte sein, dass Sie ein Objekt haben, das abgeschlossen werden muss, da Sie nicht über dispose() verfügen. (Sehr häufig mit WPF oder WinForms)

Um herauszufinden, müssen Sie einen MemoryProfiler verwenden, erwarten Sie, verbringen mindestens einen Tag schiefen, wie jeder Speicher Profiler verwenden, wie Sie mit einer Menge Daten über Objekte dargestellt werden intern in WPF. Persönlich würde ich eine kostenlose Spur von Redgate’s memory profiler herunterladen und versuchen zu sehen, was das Problem ist, da Unterstützung auch hilfreich ist. (Andere Speicher Profiler funktionieren auch gut, zu einem großen Teil hängt es nur davon ab, was Sie gewohnt sind.)

Verwandte Themen