GC - Objekt löscht sich selbst?
-
Hallo,
ich wundere mich eigentlich, warum es in der Remove Methode nicht kracht, da ja das Element das durch remove aus der Liste gelöscht wird nicht mehr referenziert wird. Hat der GC so etwas wie einen Current context um das zu verhindern?class Element { public Element(IList<Element> list) { this.list = list; } public void Remove() { list.Remove(this); GC.Collect(); System.Threading.Thread.Sleep(10000); Console.WriteLine(list.Count.ToString()); } private IList<Element> list; } class Program { public static int Main(string[] args) { List<Element> elementList = new List<Element>(); elementList.Add(new Element(elementList)); elementList[0].Remove(); return 1; } }
-
Das aktuelle Objekt ist doch über
this
erreichbar, also warum sollte der GC es löschen?
-
Zum einen wird das Objekt ja noch referenziert durch die Self-Referenz (ob das der GC berücksichtigt, ist eine andere Frage) und zum anderen greifst Du ja gar nicht auf eine Eigenschaft des assoziierten Objekts zu, sondern nur auf einige statische Methoden und das List-Objekt. Krachen würde da auch nix, wenn das Objekt bereits entfernt freigegeben wäre.
-
templäd schrieb:
Hat der GC so etwas wie einen Current context um das zu verhindern?
Der GC arbeitet so, das alle Objekte, die noch irgendwo referenziert sind, nicht gelöscht werden (Wenn du aus C++ kommst: Entfernt mit dem boost::shared_ptr vergleichbar).
-
asc schrieb:
templäd schrieb:
Hat der GC so etwas wie einen Current context um das zu verhindern?
Der GC arbeitet so, das alle Objekte, die noch irgendwo referenziert sind, nicht gelöscht werden (Wenn du aus C++ kommst: Entfernt mit dem boost::shared_ptr vergleichbar).
Eigentlich ist der Vergleich mit 'shared_ptr' grob irreführend – damit würde der obige Code auch nicht funktionieren – aber generell ist Referenzzählung einfach was anderes als die Mark&Sweep-Strategie, die der .NET-GC verwendet.
Und 'GC.Collect()' macht in diesem Zusammenhang sicherlich auch nicht das, was erwartet wird, weil der GC den Speicher ja in Generationen organisiert.
-
GC.Collect() ohne Parameter sollte laut Doku alle Generationen aufräumen.
-
Ja, aufräumen und nicht leerräumen.
-
Es kann leicht sein dass das Objekt schon gelöscht wird, obwohl noch irgendwelche Threads in Memberfunktionen des entsprechenden Objekts rumkrebsen. Allerdings nurmehr wenn das Objekt ("this") danach nichtmehr referenziert wird. D.h. wenn die Threads alle schon über "die letzten Zeile" drübergelaufen sind die irgendwelche Member des Objekts anfasst, also irgendwie "this" dereferenziert.
Im Normalfall tut das auch nicht weh. Blöd ist es nur wenn man Objekte implementiert die unmanaged Resourcen verwenden, und die unmanaged Resource noch irgendwo verwendet wird. Kann man auch in der Doku zu System.GC.KeepAlive nachlesen. In diesen Fällen kann man eben System.GC.KeepAlive verwenden um eine Referenz auf irgendetwas zu "erzwingen" so dass diese auch nicht wegoptimiert werden kann.