Gibt es einen Vorteil, Referenzen auf die .NET-Garbage-Collection zu "ermutigen"?

8

Angenommen, es gibt den folgenden Code:

%Vor%

Von Zeit zu Zeit bin ich versucht, Referenzen auf Null zu setzen, genau so wie die Prozedur beendet wird (also zurückkehrt) oder in diesem Fall, genau wie es im Begriff ist, eine Schleife zu machen. Gibt es einen Vorteil, auch wenn ein kleiner?

    
H2ONaCl 23.08.2010, 17:23
quelle

8 Antworten

12

Dies hat keinen Vorteil für lokale Variablen. Die CLR weiß mittels des JIT genau, wann eine lokale Variable innerhalb einer Methode nicht mehr verwendet wird und damit sammelbar ist.

Raymond Chen hat kürzlich einen sehr ausführlichen Blog-Artikel darüber geschrieben, wann genau Objekte gesammelt werden können. Es umfasst dieses Szenario im Detail und ist das Lesen wert

Es gibt jedoch einige Ausnahmen von dieser Regel. Wenn die fragliche lokale Variable in einem Abschluss oder einem Iterator erfasst wird, hat das Ja-Nullen der Variablen eine Auswirkung. Nämlich weil das Local nicht länger ein Local ist, sondern ein Feld und hat eine andere GC-Semantik.

    
JaredPar 23.08.2010, 17:26
quelle
4

Nein. In der Tat kann das "Nullen" lokaler Variablen unter bestimmten Umständen die Speicherbereinigung verhindern. Sobald eine Variable im normalen Betrieb nicht mehr von einem Ausführungscode aus erreichbar ist, wird sie für die Garbage Collection verfügbar. Wenn Sie am Ende Ihrer Methode die Variable "ausschließen", behalten Sie sie bis zu diesem Moment "am Leben" und verzögern tatsächlich ihre Verfügbarkeit für die Garbage Collection.

    
Mark 23.08.2010 17:25
quelle
2

Nicht, wenn die Deklaration innerhalb von Blöcken wie Sie ist. Sobald es außerhalb des Geltungsbereiches liegt, wird die Referenz automatisch ungültig und GC'd.

    
Pat 23.08.2010 17:26
quelle
2

Ich schrieb einen langen und erschöpfenden Blogartikel, der antwortet diese Frage .

Zusammenfassend lautet die allgemeine Antwort "nein; es gibt keinen Nutzen". Es gibt jedoch einige Sonderfälle:

  • Statische Felder sollten auf null gesetzt werden, wenn sie nicht mehr benötigt werden - es sei denn, der Prozess wird heruntergefahren. In diesem Fall ist es nicht erforderlich, statische Felder auf null zu setzen.
  • Lokale Variablen müssen fast nie auf null gesetzt werden. Es gibt nur eine Ausnahme: Es kann von Vorteil sein, lokale Variablen auf null zu setzen, wenn sie auf einer Nicht-Microsoft-CLR ausgeführt werden.
  • Instanzfelder müssen fast nie auf null gesetzt werden. Es gibt nur eine Ausnahme: Ein Instanzfeld kann auf null gesetzt werden, wenn erwartet wird, dass das referenzierende Objekt das referenzierte Objekt überlebt. [Beachten Sie, dass die halb übliche Vorgehensweise, Instanzfelder in IDisposable.Dispose auf null zu setzen, diesen Test nicht erfüllt und nicht empfohlen werden sollte.]

Fazit: Im Allgemeinen wird das Festlegen von Variablen auf null, um den Garbage Collector zu unterstützen, nicht empfohlen. Wenn es als notwendig erachtet wird, liegt ein ungewöhnlicher Zustand vor und sollte im Code sorgfältig dokumentiert werden.

    
Stephen Cleary 23.08.2010 17:56
quelle
2

Wenn eine Klasse über einen Finalizer verfügt, führen alle Nicht-Null-Objektreferenzfelder dazu, dass die Objekte, auf die verwiesen wird, länger gehalten werden als sie es sonst tun würden. Wenn bekannt ist, dass die Objekte bereits vor Ausführung des Finalizers nicht mehr benötigt werden, können durch das Entfernen der Objektreferenzfelder die Objekte früher "generiert" werden, als dies sonst der Fall wäre. Das kann ein großer Gewinn sein.

Wenn erwartet wird, dass die Lebensdauer (nützlich oder nicht) eines Objekts die nutzbare Lebensdauer eines Objekts übertrifft, auf das es eine Referenz hat, verhindert das unnötige Halten einer Referenz, dass das letzte Objekt erfasst wird, bis das erstere ist Referenz wird zwingen, das letztere Objekt zu behalten, selbst nachdem es nutzlos geworden ist). Durch das Löschen der Referenz wird dieses Problem vermieden.

Wenn eine in vb.net geschriebene Klasse irgendwelche "WithEvents-Variablen" hat, sollten sie jedes Mal gelöscht werden (setzen Sie sie auf nichts), wenn das Objekt, das sie enthält, nutzlos wird. Eine Klasse kann nicht als Garbage-Collection betrachtet werden, wenn sie einen Verweis auf ein Live-Objekt in einer "WithEvents-Variablen" enthält. Wenn z.B. Ein Enumerator enthält eine "WithEvents" -Referenz auf eine zugrunde liegende Sammlung (z. B. kann er Ereignisse empfangen, wenn / wenn die Sammlung geändert wird) und sein Dispose-Handler seinen Verweis auf die zugrunde liegende Sammlung nicht löscht. Der Enumerator wird solange am Leben gehalten die zugrunde liegende Sammlung ist. Wenn die Auflistung sehr oft aufgezählt wird, könnte dies zu einem massiven Speicherverlust führen.

    
supercat 23.08.2010 18:17
quelle
1

Nein. Lass den GC seine Arbeit machen und hilf ihm nur wenn es nötig ist.

    
Kent Boogaart 23.08.2010 17:26
quelle
0

Es gibt einen wichtigen Fall, in dem das Nullen eine Auswirkung hat, wenn Sie einen Debug-Build mit einigen deaktivierten JIT-Optimierungen verwenden. Ein Großteil des Funker-Verhaltens, wenn Objekte aufgeräumt werden, kann aufhören, das Debuggen zu erleichtern.

Es ist wichtig, weil es zu einer falschen Sicht auf das, was im Release-Build passiert, führen kann.

    
Jon Hanna 23.08.2010 19:12
quelle
0

Und die Antwort ist: Ja, wenn Sie wissen, was Sie tun! Aber es ist vorzeitige Optimierung (die Wurzel aller Übel für viele Personen), also sollten Sie es nicht tun, es sei denn, Sie brauchen wirklich den Speicher.

Nun werde ich nur zwei Fälle analysieren, in denen es nützlich sein könnte.

  • Eigenschaften eines Objekts, von dem Sie wissen, dass es nicht mehr referenziert wird (zum Beispiel haben Sie eine komplexe Berechnung in einer privaten Eigenschaft zwischengespeichert. Sie wissen, dass Sie nicht mehr brauchen werden, Sie säubern es) Aber dieses wurde gesagt von vielen Personen

  • Felder in komplexen Methoden. Dies ist das Gegenteil von dem, was andere gesagt haben, aber ich habe ein Beispiel, also weiß ich, dass ich recht habe :-) Nun, normalerweise, in einer sequentiellen Methode kann der GC sehen, wo ein lokaler ist Die Referenz wird nicht mehr verwendet (technisch gesehen ist der wichtigste Teil, wenn sie nicht mehr gelesen wird. Und das Aufrufen von Methoden der Variablen ist "Lesen". Das Schreiben in eine Variable zählt nicht, denn wenn niemand den neuen Wert liest, ist es nutzlos schreibe es)

Aber ich habe sequentielle Methode gesagt. Und nicht sequentielle Methoden? Lass es uns versuchen! (Klar habe ich es schon gemacht! Ich werde kein ideone Beispiel machen, weil der GC von mono anders ist als der GC von .NET).

Kompilieren Sie diesen Code im Modus Release und führen Sie ohne den Debugger (also STRG-F5) aus, und beobachten Sie die Ergebnisse:

%Vor%

Die Ergebnisse:

%Vor%

Eine Erklärung: Dieses Programm ist ein Beispiel für ein zyklisches Programm, bei dem ein großes Objekt außerhalb des Zyklus initialisiert wird (a for cycle) und das große Objekt nur in einem Teil des Zyklus verwendet wird (zum Beispiel in den ersten 100) Iterationen). Offensichtlich kann der GC nicht leicht erkennen, dass ab dem Ende der Iteration 99 (der 100. Iteration, 0-99) auf das Objekt nicht mehr Bezug genommen wird.

Aber erinnere dich an die Worte vorzeitige Optimierung und Wurzel aller Übel ! : -)

    
xanatos 21.10.2011 06:15
quelle

Tags und Links