2010-01-21 11 views
8

Sollte ein einfacher sein. Lassen Sie uns sagen, dass ich den folgenden Code haben:C# .NET Objekt Entsorgung

void Method() 
{ 
    AnotherMethod(new MyClass()); 
} 

void AnotherMethod(MyClass obj) 
{ 
    Console.WriteLine(obj.ToString()); 
} 

Wenn ich „Method()“ nennen, was dem MyClass-Objekt geschieht, die in dem Prozess erstellt wurde? Ist es nach dem Aufruf noch im Stack vorhanden, obwohl es nichts verwendet? Oder wird es sofort entfernt?

Muss ich es auf null setzen, damit GC es schneller bemerkt?

+0

Im Gegensatz zu C++ leben Objekte in Sprachen wie Java/C# nicht auf dem Stack; Nur Referenzen auf die Objekte, die Objekte selbst sind auf dem Heap. –

Antwort

7

Wenn ich "Method()" aufrufen, was passiert mit dem MyClass-Objekt, das im Prozess erstellt wurde?

Es wird auf dem GC-Heap erstellt. Dann wird ein Verweis auf seine Position im Heap auf den Stapel gelegt. Dann passiert der Aufruf von AnotherMethod. Dann wird die ToString-Methode des Objekts aufgerufen und das Ergebnis ausgedruckt. Dann kommt AnotherMethod zurück.

Ist es nach dem Anruf immer noch im Stapel vorhanden, obwohl es nichts verwendet?

Ihre Frage ist mehrdeutig. Mit "der Anruf" meinen Sie den Aufruf von Methode oder AnotherMethod? Es macht einen Unterschied, denn an dieser Stelle hängt es davon ab, ob Sie mit optimierten oder deaktivierten Optimierungen kompiliert haben, ob der Heap-Speicher ein Kandidat für die Garbage Collection ist. Ich werde Ihr Programm leicht ändern, um den Unterschied zu veranschaulichen. Angenommen, Sie haben:

void Method() 
{ 
    AnotherMethod(new MyClass()); 
    Console.WriteLine("Hello world"); 
} 

Mit Optimierungen aus, wir manchmal tatsächlich Code erzeugen, der so sein würde:

void Method() 
{ 
    var temp = new MyClass(); 
    AnotherMethod(temp); 
    Console.WriteLine("Hello world"); 
} 

In der nicht optimierten Version, wird die Laufzeit wählen, tatsächlich das Objekt als nicht- zu behandeln sammelbar, bis Method nach der WriteLine zurückkehrt. In der optimierten Version kann die Laufzeitumgebung das Objekt als sammelbar behandeln, sobald AnotherMethod zurückgegeben wird, vor der WriteLine.

Der Grund für den Unterschied liegt darin, dass die Lebensdauer der Objekte während der Debugging-Sitzungen vorhersagbarer wird, was den Leuten hilft, ihre Programme besser zu verstehen.

Oder wird es sofort entfernt?

Nichts wird sofort gesammelt; Der Müllsammler läuft, wenn es sich anfühlt, als müsste es laufen. Wenn Sie eine Ressource wie ein Datei-Handle benötigen, das sofort bereinigt wird, wenn Sie damit fertig sind, verwenden Sie einen "using" -Block. Wenn nicht, dann sollte der Garbage Collector entscheiden, wann er Speicher sammeln soll.

Muss ich es auf null setzen, damit GC es schneller bemerkt?

Müssen Sie was auf null setzen? Welche Variable hatten Sie im Sinn?

Unabhängig davon, haben Sie nicht haben, alles zu tun, um den Garbage Collector arbeiten zu lassen. Es läuft für sich alleine gut ohne Aufforderung von Ihnen.

Ich denke, dass Sie dieses Problem überdenken. Lass den Müllsammler sein Ding machen und betone nicht darüber. Wenn Sie ein Problem mit der realen Welt haben, bei dem der Speicher nicht rechtzeitig erfasst wird, zeigen Sie uns einen Code, der das Problem veranschaulicht. Ansonsten, entspannen Sie sich und lernen Sie die automatische Speicherregenerierung zu lieben.

+0

Große Antwort! Wenn ich sagte, "setze auf Null", in Ihrem zweiten Beispiel (Optimierungen aus), wäre es dasselbe wie "temp = null", nachdem ich es in AnotherMethod verwende. Grund, dass ich dieses Problem habe, ist, dass ich eine Exception in meinem Code nicht serialisieren konnte. Angenommen, Method() existiert in "TopClass". Ich habe "TopClass" als serialisierbar markiert. MyClass kann nicht serialisiert werden. Ich dachte, dass GC nicht schnell genug agierte und ein nicht-serialisierbares Objekt (MyClass) in einem serialisierbaren Objekt belassen wurde. Der Versuch, "TopClass" zu serialisieren, würde dann eine Ausnahme auslösen. – Nick

+2

Ich denke, dass Ihre Hypothese das Serialisierungsproblem tatsächlich nicht erklären wird. Gibt es vielleicht ein * Feld * Ihres Objekts, das eine Referenz auf ein nicht serialisierbares Objekt enthält? –

+0

Vereinbaren Sie Eric Lippert über Serialisierung (und wem bin ich nicht einverstanden). Bei der Serialisierung geht es um die Daten eines Typs, nicht um den Code. Alles "Lokale" zu einer Methode sollte nicht wichtig sein. –

13

Nachdem der Aufruf von Method abgeschlossen wurde, ist Ihr MyClass Objekt noch aktiv, aber es gibt keine Verweise darauf von einem verwurzelten Wert. So wird es bis zum nächsten Mal, wo der GC läuft, leben, wo er gesammelt und der Speicher zurückgewonnen wird.

Es gibt wirklich nichts, was Sie tun können, um diesen Prozess zu beschleunigen, außer einen GC zu erzwingen. Dies ist jedoch wahrscheinlich eine schlechte Idee. Der GC wurde entwickelt, um solche Objekte zu bereinigen, und jeder Versuch, ihn zu beschleunigen, wird wahrscheinlich dazu führen, dass er insgesamt langsamer wird. Sie werden auch feststellen, dass ein GC während der korrekten Bereinigung verwalteter Objekte den Speicher in Ihrem System möglicherweise nicht wirklich reduziert. Dies liegt daran, dass der GC ihn für die zukünftige Verwendung bereithält. Es ist ein sehr komplexes System, das am besten den eigenen Geräten überlassen wird.

+1

Schau nicht auf den Mann hinter dem Vorhang! :) Ich genieße es, all das für den GC zu belassen. Eine Sache weniger, über die man sich Sorgen machen muss. –

-4

Soweit ich weiß, ist das Objekt nur innerhalb Ihres Methodenkontextes gültig. Nachdem die Methode "Method()" ausgeführt wurde, wird sie der Verfügungswarteschlange hinzugefügt.

+0

Worum handelt es sich bei dieser "Dispo-Warteschlange"? Ich habe noch nie davon gehört. Kannst du erklären, was du meinst? –

+0

Ich meine, dass das Objekt als "verfügbar zu disponieren" markiert ist. Ich habe gelesen, dass diese Objekte zu einer Warteschlange hinzugefügt werden, um vom GC entsorgt zu werden. – lluismontero

+0

Ich denke, Sie denken an die ausstehenden Finalizer. Ihre Aussage ist streng genommen korrekt; Die Objektreferenz ist nur solange gültig, bis die Methode beendet wird. Und zu einem Zeitpunkt * nach der Methode wird der Garbage Collector schließlich feststellen, dass das Objekt nicht mehr verwurzelt ist, es für die Finalisierung markieren, es finalisieren und den Speicher an den GC-Heap zurückgeben. Aber es ist falsch, den GC so zu charakterisieren, dass er tote Objekte in die Warteschlange stellt, wenn die Kontrolle alle Methoden verlässt; das ist überhaupt nicht wie es funktioniert. –

3

Eigentlich wird die Instanz auf dem Heap deklariert, aber sehen Sie sich Eric Lippers Artikel The Stack is an Implementation Detail an.

In jedem Fall wird es (oder genauer gesagt kann sein) gelöscht werden durch den Garbage Collector an einem nicht definierten Punkt in der Zukunft, da es keine Referenzen mehr auf die Instanz nach der Ausführung der Funktion geben wird. Wann genau das passiert, ist nicht definiert, aber Sie müssen sich auch (im Wesentlichen) nicht darum kümmern; Der GC hat komplizierte Algorithmen, mit denen er bestimmen kann, was und wann er sammeln soll.

2

In C# ist die neue MyClass() nur auf den Bereich innerhalb von Method() beschränkt, solange sie aktiv ist. Sobald die Ausführung von AnotherMethod() abgeschlossen ist, ist der Bereich nicht mehr gültig und wird nicht mehr ausgeführt. Es verbleibt dann auf dem Heap, bis der GC seinen Erfassungszyklus ausführt und ihn als nicht referenzierten Speicherblock identifiziert. So ist es auf dem Haufen noch "lebendig", aber es ist nicht zugänglich.

3

gibt es sie noch in dem Stapel nach dem Aufruf

Semantics hier wichtig sind. Sie haben gefragt, ob es nach dem Methodenaufruf auf dem Stack noch vorhanden ist. Die Antwort ist "Nein". Es wurde vom Stapel entfernt. Aber das ist nicht die letzte Geschichte. Das Objekt existiert immer noch, es ist einfach nicht mehr verwurzelt. Es wird nicht zerstört oder gesammelt, bis der GC läuft. Aber an diesem Punkt geht es nicht länger um Sie. Der GC ist viel besser darin zu entscheiden, wann man etwas sammelt, als du oder ich.

Muss ich es auf null setzen, damit GC es schneller bemerkt?

Dafür gibt es fast nie einen guten Grund. Die einzige Zeit, die hilft, ist, wenn Sie eine sehr lange laufende Methode und ein Objekt haben, mit dem Sie früh fertig sind, das sonst nicht bis zum Ende der Methode aus dem Geltungsbereich wird. Selbst dann, wenn Sie ihn auf null setzen, hilft das nur in dem seltenen Fall, in dem der GC entscheidet, während der Methode zu laufen. Aber in diesem Fall machst du wahrscheinlich auch etwas anderes falsch.

+2

Tatsächlich kann der CLR GC * eine Nicht-Null-Variable bereinigen, während eine Methode ausgeführt wird, wenn sie feststellen kann, dass die Variable für den Rest der Methode nicht verwendet wird. Deshalb muss 'GC.KeepAlive()' existieren (obwohl Sie diese Methode niemals verwenden sollten, wenn Sie nicht wirklich * wirklich * müssen). Wenn man also eine Variable auf null setzt, sollte das überhaupt keinen Unterschied machen. –

1

Der GC verfolgt, welche Objekte möglicherweise später noch im Code referenziert werden. Dann überprüft es in Intervallen, ob noch Objekte vorhanden sind, auf die später nicht mehr im Code verwiesen werden kann, und bereinigt sie.

Die Mechanik ist etwas komplex und hängt von einer Vielzahl von Faktoren ab. Der GC ist so konzipiert, dass er diese Sammlungen zum optimalen Zeitpunkt ausführt (was er feststellen kann), und obwohl es möglich ist, eine Sammlung zu erzwingen, ist dies fast immer eine schlechte Idee.

Wenn Sie die Variable auf null setzen, wirkt sich dies nur sehr wenig auf die Verarbeitung des Objekts aus. Während es in einigen kleinen Fällen von Vorteil sein kann, lohnt es sich nicht, Ihren Code mit redundanten Zuweisungen zu versehen, die die Code-Leistung nicht beeinträchtigen und nur die Lesbarkeit beeinträchtigen.

Der GC wurde so konzipiert, dass er so effektiv wie möglich ist, ohne dass Sie darüber nachdenken müssen. Um ehrlich zu sein, ist das Einzige, worauf man wirklich achten muss, vorsichtig zu sein, wenn man wirklich große Objekte zuordnet, die für lange Zeit am Leben bleiben werden, und das ist in meiner Erfahrung ziemlich selten.

Verwandte Themen