C # .NET Objekt Entsorgung

8

Sollte einfach sein. Sagen wir, ich habe den folgenden Code:

%Vor%

Was passiert beim Aufruf von "Method ()" mit dem MyClass-Objekt, das dabei 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?

    
Nick 21.01.2010, 16:55
quelle

7 Antworten

7
  

Was passiert beim Aufruf von "Method ()" mit dem MyClass-Objekt, das dabei 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 Aufruf immer noch im Stack 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 Heapspeicher ein Kandidat für die Garbage Collection ist. Ich werde Ihr Programm leicht ändern, um den Unterschied zu veranschaulichen. Angenommen, du hättest:

%Vor%

Wenn die Optimierungen deaktiviert sind, generieren wir manchmal Code, der wie folgt aussieht:

%Vor%

In der nicht optimierten Version wählt die Laufzeitumgebung das Objekt als nicht sammelbar, bis Methode 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, um den Benutzern zu helfen, 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 müssen Sie nichts tun, damit der Garbage Collector funktioniert. Es läuft für sich allein gut, ohne von Ihnen zu fragen.

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.

    
Eric Lippert 21.01.2010, 17:38
quelle
13

Nachdem der Aufruf von Method abgeschlossen ist, ist Ihr MyClass -Objekt am Leben, 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 schneller zu machen, 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 man am besten seinen eigenen Geräten überlassen sollte.

    
JaredPar 21.01.2010 16:57
quelle
3

Tatsächlich wird die Instanz auf dem Heap deklariert, aber werfen Sie einen Blick auf Eric Lippers Artikel Der Stack ist ein Implementierungsdetail .

Da nach der Ausführung der Funktion keine weiteren Verweise auf die Instanz vorhanden sind, wird (oder genauer gesagt, kann ) vom Speicherbereiniger an einem nicht definierten Punkt gelöscht werden in der Zukunft. Wann genau das passiert, ist nicht definiert, aber Sie müssen sich auch (im Wesentlichen) nicht darum kümmern; Der GC hat komplizierte Algorithmen, die ihm helfen zu bestimmen, was und wann zu sammeln ist.

    
Adam Robinson 21.01.2010 16:57
quelle
3
  

Ist es nach dem Aufruf noch im Stapel vorhanden?

Semantik ist hier wichtig. Sie haben gefragt, ob es nach dem Methodenaufruf noch auf dem Stack 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.

    
Joel Coehoorn 21.01.2010 17:13
quelle
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. Es ist also immer noch auf dem Heap "lebendig", aber es ist nicht zugänglich.

    
Joel Etherton 21.01.2010 16:58
quelle
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 Mechanismen hierfür sind etwas komplex, und wann diese Sammlungen passieren werden, 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 Nutzen 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.

    
ICR 21.01.2010 17:17
quelle
-4

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

    
lluismontero 21.01.2010 16:57
quelle