8 Stimmen

Wie funktioniert die Garbage Collection bei Objektreferenzen?

Ich bin verwirrt über den Garbage Collection-Prozess für Objekte.

object A = new object();
object B = A;        
B.Dispose();

Durch einen Dispose-Aufruf nur für die Variable B wird das erstellte Objekt nicht in den Müll geworfen. da das Objekt immer noch von A referenziert wird.

Funktioniert der folgende Code genauso wie der obige?

public static image Test1()
{
    Bitmap A = new Bitmap();
    return A;
}

Jetzt rufe ich diese statische Funktion von einer anderen Methode aus auf.

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 

Die statische Funktion Test1 gibt einen Verweis auf das Bitmap-Objekt zurück. Der Verweis wird gespeichert Die Referenz wird in einer anderen Variablen B gespeichert. Durch den Aufruf von Dispose für B wird die Verbindung zwischen B und dem Objekt unterbrochen, aber was geschieht mit der von Test1 übergebenen Referenz? Bleibt sie aktiv, bis der Anwendungsbereich der Funktion TestB beendet ist?

Gibt es eine Möglichkeit, die Referenz, die von der statischen Funktion übergeben wird, sofort zu entsorgen?

18voto

Jon Skeet Punkte 1325502

Dispose hace no Müllsammeln. Sie können ein bestimmtes Objekt nicht explizit garbage collecten. Sie können GC.Collect() die Anfragen dass der Garbage Collector läuft, aber das ist nicht dasselbe. Aufruf von Dispose nicht einmal "trennen" das Objekt von einer bestimmten Variable, in der Tat ... während diese Variable live bleibt (bis zum letzten Mal die JIT erkennen kann, dass es jemals wieder gelesen werden) es wird das Objekt von Garbage Collect verhindert werden.

Ein Objekt wird erst dann entsorgt, wenn es nicht mehr von anderen Objekten referenziert wird. Zugegebenermaßen kann dies in einigen extremen Fällen früher der Fall sein, als Sie vielleicht denken, aber darüber müssen Sie sich selten Gedanken machen.

Es ist wichtig zu wissen, dass Dispose und Müllabfuhr sind sehr unterschiedliche Dinge. Sie rufen Dispose zur Freigabe unverwaltet Ressourcen (Netzverbindungen usw.). Die Speicherbereinigung dient ausschließlich der Freigabe von Speicher. Zugegebenermaßen kann die Garbage Collection durch eine Finalisierung erfolgen, die als letzten Ausweg nicht verwaltete Ressourcen freigeben kann, aber die meiste Zeit sollten Sie nicht verwaltete Ressourcen explizit entsorgen.

16voto

Yuriy Faktorovich Punkte 64670

Ich mag mich irren, aber Sie scheinen ein Missverständnis zu haben Dispose und Garbage Collection. Ein Objekt wird garbage collected, sobald alle Verweise auf das Objekt verschwunden sind, und zwar auf nicht-deterministische Weise. Mit Dispose werden normalerweise die nicht verwalteten Ressourcen beseitigt, so dass das Objekt für die Garbage Collection bereit ist. In Ihrem ersten Beispiel haben Sie das Objekt entsorgt und es damit theoretisch unbrauchbar gemacht, aber es existiert immer noch auf dem Heap und Sie haben immer noch eine Referenz darauf, sowohl A als auch B. Sobald diese aus dem Anwendungsbereich verschwinden, kann der Garbage Collector diesen Speicher zurückfordern, aber nicht immer. In Beispiel 2 wird eine Bitmap A auf dem Heap abgelegt, dann gibt man eine Referenz darauf zurück und setzt B auf diese Referenz. Dann wird die Bitmap entsorgt, und B verschwindet aus dem Anwendungsbereich. Zu diesem Zeitpunkt gibt es keine Verweise mehr auf die Bitmap A, und sie wird zu einem späteren Zeitpunkt entsorgt.

5voto

Daniel Pratt Punkte 11859

Es kommt vor, dass Raymond Chen hat gerade eine Reihe von Blogbeiträgen geschrieben, die Aspekte der .NET-Garbage Collection beschreiben. Diese Stelle steht in direktem Zusammenhang mit Ihrer Frage (wann werden Gegenstände im Müll gesammelt?).

3voto

siride Punkte 184124

Dispose() hat nichts mit der Garbage Collection zu tun. Es ermöglicht lediglich die deterministische Freigabe von Ressourcen, aber Sie müssen es explizit aufrufen. Das Objekt, das Sie damit aufrufen, wird nicht in den Müll geworfen, wenn Sie Dispose() aufrufen. Es kommt für die Garbage Collection in Frage, wenn alle Verweise auf es verschwunden sind.

2voto

Viele gute Antworten hier, aber ich möchte auch darauf hinweisen, dass der Grund, dass die Leute dachten, Sie benötigt IDisposable ist, dass ein GC wirklich MemoryCollector oder sogar ManagedMemoryCollector genannt werden sollte. Ein GC ist nicht besonders intelligent, wenn es darum geht, nicht verwaltete Speicherressourcen wie Dateien, Datenbankkonten, Transaktionen, Windows-Handles und so weiter zu sammeln.

Einer der Gründe dafür ist, dass ein verwaltetes Objekt eine nicht verwaltete Ressource haben kann, die mehrere Gigabyte Speicherplatz benötigt, aber für den GC wie 8 Byte oder so aussieht.

Bei Dateien, Datenbankkonten usw. möchte man sie oft so schnell wie möglich schließen, um nicht verwaltete Ressourcen freizugeben und Sperrprobleme zu vermeiden.

Bei Windows-Handles müssen wir uns um die Thread-Affinität kümmern. Da eine GC in einem eigenen Thread läuft, ist dieser Thread immer der falsche Thread für die Freigabe von Windows-Handles.

GC hilft also sehr dabei, das Auslaufen von verwaltetem Speicher zu vermeiden und das Code-Wirrwarr zu reduzieren, aber man sollte dennoch nicht verwaltete Ressourcen so schnell wie möglich freigeben.

Die Anweisung () ist ein Segen.

PS. Ziemlich oft implementiere ich IDisposable, obwohl ich keine direkten unverwalteten Ressourcen habe. Es ist jedoch wichtig, alle Membervariablen, die IDisposable implementieren, zu informieren, dass Dispose aufgerufen wurde.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X