Sollten Sie alle Objekte auf null
( Nothing
in VB.NET) setzen, wenn Sie damit fertig sind?
Ich verstehe, dass es in .NET wichtig ist, alle Instanzen von Objekten zu entsorgen, die die IDisposable
Schnittstelle implementieren , um einige Ressourcen freizugeben, obwohl das Objekt nach dem Entsorgen noch etwas sein kann (daher die isDisposed
Eigenschaft in Formularen), daher gehe ich davon aus, dass es sich noch befinden kann im Gedächtnis oder zumindest teilweise?
Ich weiß auch, dass ein Objekt, wenn es den Gültigkeitsbereich verlässt, zur Sammlung markiert wird und für den nächsten Durchgang des Garbage Collectors bereit ist (obwohl dies einige Zeit dauern kann).
In diesem Sinne wird es so eingestellt null
, dass es das System beschleunigt, das den Speicher freigibt, da es nicht herausfinden muss, dass es nicht mehr im Umfang ist und es irgendwelche schlechten Nebenwirkungen gibt?
MSDN-Artikel tun dies niemals in Beispielen, und derzeit mache ich dies, da ich den Schaden nicht sehen kann. Ich bin jedoch auf eine Mischung von Meinungen gestoßen, sodass Kommentare nützlich sind.
Antworten:
Karl ist absolut korrekt, es besteht keine Notwendigkeit, Objekte nach der Verwendung auf null zu setzen. Wenn ein Objekt implementiert wird
IDisposable
, stellen Sie einfach sicher, dass Sie aufrufen,IDisposable.Dispose()
wenn Sie mit diesem Objekt fertig sind (eingeschlossen in einentry
..finally
oder einenusing()
Block). Aber selbst wenn Sie nicht daran denken, aufzurufenDispose()
, sollte die Finaliser-Methode für das ObjektDispose()
für Sie aufrufen .Ich fand das eine gute Behandlung:
und das
Es macht keinen Sinn, den GC und seine Managementstrategien zu erraten, da er sich selbst abstimmt und undurchsichtig ist. Es gab hier eine gute Diskussion über das Innenleben mit Jeffrey Richter auf Dot Net Rocks: Jeffrey Richter über das Windows-Speichermodell und Richters Buch CLR über C # Kapitel 20 hat eine großartige Behandlung:
quelle
Ein weiterer Grund, um zu vermeiden, dass Objekte auf Null gesetzt werden, wenn Sie damit fertig sind, besteht darin, dass sie tatsächlich länger am Leben bleiben können.
z.B
ermöglicht es dem Objekt, auf das von someType verwiesen wird, nach dem Aufruf von "DoSomething" aber GC zu werden
kann manchmal das Objekt bis zum Ende der Methode am Leben halten. Die JIT optimiert normalerweise die Zuweisung auf Null , sodass beide Codebits am Ende gleich sind.
quelle
GC.KeepAlive(someType);
Siehe ericlippert.com/2013/06/10/construction-destructionNein, keine Objekte auf Null setzen. Weitere Informationen finden Sie unter http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx auf null wird nichts tun, außer Ihren Code zu verschmutzen.
quelle
Ebenfalls:
quelle
Im Allgemeinen müssen Objekte nach der Verwendung nicht auf Null gesetzt werden, aber in einigen Fällen ist dies eine gute Vorgehensweise.
Wenn ein Objekt IDisposable implementiert und in einem Feld gespeichert ist, ist es meiner Meinung nach gut, es auf Null zu setzen, nur um die Verwendung des entsorgten Objekts zu vermeiden. Die Fehler der folgenden Art können schmerzhaft sein:
Es ist gut, das Feld nach dem Entsorgen auf Null zu setzen und einen NullPtrEx direkt an der Zeile zu erhalten, an der das Feld erneut verwendet wird. Andernfalls könnten Sie später auf einen kryptischen Fehler stoßen (abhängig davon, was DoSomething genau tut).
quelle
.Dispose()
. Wenn Sie es finden, verwenden Sie IDisposable nicht richtig. Die einzige Verwendung für ein Einwegobjekt sollte in den Grenzen eines Verwendungsblocks liegen. Und nach dem using-Block haben Sie nicht einmal mehr Zugriff daraufmyField
. Und innerhalb des using-Blocks ist die Einstellung aufnull
nicht erforderlich. Der using-Block entsorgt das Objekt für Sie.Es besteht die Möglichkeit, dass Ihr Code nicht eng genug strukturiert ist, wenn Sie das Bedürfnis nach
null
Variablen haben.Es gibt verschiedene Möglichkeiten, den Umfang einer Variablen einzuschränken:
Wie von Steve Tranby erwähnt
Ebenso können Sie einfach geschweifte Klammern verwenden:
Ich finde, dass geschweifte Klammern ohne "Überschrift" verwendet werden, um den Code wirklich zu bereinigen und ihn verständlicher zu machen.
quelle
Sie sollten eine Variable nur dann auf null setzen, wenn die Variable den Gültigkeitsbereich nicht verlässt und Sie die damit verbundenen Daten nicht mehr benötigen. Ansonsten besteht keine Notwendigkeit.
quelle
Im Allgemeinen muss nicht auf null gesetzt werden. Angenommen, Sie haben eine Reset-Funktion in Ihrer Klasse.
Dann können Sie dies tun, da Sie dispose nicht zweimal aufrufen möchten, da einige der Dispose möglicherweise nicht korrekt implementiert sind und die Ausnahme System.ObjectDisposed auslösen.
quelle
Diese Art von "Es ist nicht erforderlich, Objekte nach der Verwendung auf Null zu setzen" ist nicht ganz korrekt. Es gibt Zeiten, in denen Sie die Variable NULL machen müssen, nachdem Sie sie entsorgt haben.
Ja, Sie sollten IMMER anrufen
.Dispose()
oder.Close()
auf etwas, das es hat, wenn Sie fertig sind. Sei es Dateihandles, Datenbankverbindungen oder Einwegobjekte.Davon abgesehen ist das sehr praktische Muster von LazyLoad.
Sagen , ich habe und instanziiert
ObjA
vonclass A
.Class A
hat eine öffentliche Eigenschaft namensPropB
vonclass B
.PropB
Verwendet intern die private Variable von_B
und ist standardmäßig null. WennPropB.Get()
es verwendet wird, wird überprüft, ob_PropB
es null ist, und wenn dies der Fall ist, werden die Ressourcen geöffnet, die zum Instanziieren von aB
in erforderlich sind_PropB
. Es kehrt dann zurück_PropB
.Nach meiner Erfahrung ist dies ein wirklich nützlicher Trick.
Wenn Sie A auf eine Weise zurücksetzen oder ändern, bei der der Inhalt
_PropB
das untergeordnete Element der vorherigen Werte von warA
, müssen Sie Dispose AND null out zurücksetzen oder ändern ,_PropB
damit LazyLoad zurückgesetzt werden kann, um den richtigen Wert für den Code abzurufen erfordert es.Wenn Sie dies nur tun
_PropB.Dispose()
und kurz darauf erwarten, dass die Nullprüfung für LazyLoad erfolgreich ist, wird sie nicht null sein und Sie werden veraltete Daten anzeigen. In der Tat müssen Sie es nach null auf Null setzen,Dispose()
nur um sicherzugehen.Ich wünsche , dass es anders, aber ich habe jetzt bekomme Code , um dieses Verhaltens nach einer ausstellenden
Dispose()
auf einem_PropB
und außerhalb der anrufenden Funktion, die das Entsorgen tat (und damit fast der Gültigkeitsbereich), die private prop ist noch nicht null, und die veralteten Daten sind immer noch da.Letztendlich wird die veräußerte Eigenschaft auf Null gesetzt, aber das war aus meiner Sicht nicht deterministisch.
Der Hauptgrund, wie dbkk anspielt, ist, dass der übergeordnete Container (
ObjA
mitPropB
) die Instanz_PropB
trotz des Gültigkeitsbereichs behältDispose()
.quelle
In einigen Fällen ist es sinnvoll, Referenzen auf Null zu setzen. Wenn Sie beispielsweise eine Sammlung schreiben - wie eine Prioritätswarteschlange - und gemäß Ihrem Vertrag, sollten Sie diese Objekte für den Client nicht am Leben erhalten, nachdem der Client sie aus der Warteschlange entfernt hat.
Aber so etwas ist nur in langlebigen Sammlungen von Bedeutung. Wenn die Warteschlange das Ende der Funktion, in der sie erstellt wurde, nicht überlebt, ist dies viel weniger wichtig.
Im Großen und Ganzen sollten Sie sich wirklich nicht darum kümmern. Lassen Sie den Compiler und GC ihre Arbeit erledigen, damit Sie Ihre erledigen können.
quelle
Schauen Sie sich auch diesen Artikel an: http://www.codeproject.com/KB/cs/idisposable.aspx
Das Setzen eines Objekts auf null hat größtenteils keine Auswirkung. Sie sollten dies nur dann tun, wenn Sie mit einem "großen Objekt" arbeiten, das größer als 84 KB ist (z. B. Bitmaps).
quelle
Stephen Cleary erklärt in diesem Beitrag sehr gut: Soll ich Variablen auf Null setzen, um die Speicherbereinigung zu unterstützen?
Sagt:
Das Wichtige, was wir berücksichtigen sollten, sind statische Felder .
Fazit:
quelle
Ich glaube, durch das Design der GC-Implementierer kann man GC nicht durch Nullifizierung beschleunigen . Ich bin sicher, sie würden es vorziehen, wenn Sie sich keine Gedanken darüber machen, wie / wann GC läuft - behandeln Sie es wie dieses allgegenwärtige Wesen, das Sie beschützt und auf Sie aufpasst ... (verbeugt sich mit gesenktem Kopf, hebt die Faust zum Himmel). .
Persönlich setze ich Variablen oft explizit auf null, wenn ich mit ihnen als Form der Selbstdokumentation fertig bin. Ich deklariere nicht, benutze es und setze es später auf null - ich nulle sofort, nachdem sie nicht mehr benötigt werden. Ich sage ausdrücklich: "Ich bin offiziell mit dir fertig ... sei weg ..."
Ist eine Aufhebung in einer GC-Sprache erforderlich? Ist es hilfreich für den GC? Vielleicht ja, vielleicht nein, weiß es nicht genau, von Natur aus kann ich es wirklich nicht kontrollieren, und unabhängig von der heutigen Antwort mit dieser oder jener Version könnten zukünftige GC-Implementierungen die Antwort außerhalb meiner Kontrolle ändern. Und wenn / wenn die Nullung optimiert ist, ist es kaum mehr als ein ausgefallener Kommentar, wenn Sie so wollen.
Ich denke , wenn es meine Absicht klarer auf die nächste arme Narr, der in meine Fußstapfen folgt macht, und wenn es „könnte“ potenziell manchmal Hilfe GC, dann lohnt es sich , es mir. Meistens fühle ich mich dadurch ordentlich und klar, und Mongo fühlt sich gerne ordentlich und klar. :) :)
Ich sehe das so: Es gibt Programmiersprachen, mit denen Leute anderen eine Vorstellung von der Absicht geben können und einem Compiler eine Jobanfrage, was zu tun ist - der Compiler konvertiert diese Anfrage in eine andere Sprache (manchmal mehrere) für eine CPU - Die CPU (s) können einen Hinweis darauf geben, welche Sprache Sie verwendet haben, welche Registerkarteneinstellungen, Kommentare, Stilschwerpunkte, Variablennamen usw. - bei einer CPU dreht sich alles um den Bitstrom, der angibt, welche Register und Opcodes und Speicherorte zu ändern sind. Viele in Code geschriebene Dinge werden nicht in der von uns angegebenen Reihenfolge in das konvertiert, was von der CPU verbraucht wird. Unser C, C ++, C #, Lisp, Babel, Assembler oder was auch immer eher Theorie als Realität ist, geschrieben als Arbeitserklärung. Was Sie sehen, ist nicht das, was Sie bekommen, ja, selbst in Assembler-Sprache.
Ich verstehe die Denkweise von "unnötigen Dingen" (wie Leerzeilen) "sind nichts als Rauschen und unübersichtlicher Code." Das war ich früher in meiner Karriere; Das verstehe ich total. An dieser Stelle neige ich zu dem, was den Code klarer macht. Es ist nicht so, dass ich meinen Programmen sogar 50 Zeilen "Rauschen" hinzufüge - es sind hier oder da ein paar Zeilen.
Es gibt Ausnahmen zu jeder Regel. In Szenarien mit flüchtigem Speicher, statischem Speicher, Rennbedingungen, Singletons, Verwendung "veralteter" Daten und all dieser Art von Fäulnis ist das anders: Sie MÜSSEN Ihren eigenen Speicher verwalten, als Apropos sperren und aufheben, da der Speicher nicht Teil von ist das GC'd Universum - hoffentlich versteht das jeder. Der Rest der Zeit mit GC-Sprachen ist eher eine Frage des Stils als der Notwendigkeit oder einer garantierten Leistungssteigerung.
Stellen Sie am Ende des Tages sicher, dass Sie verstehen, was für GC in Frage kommt und was nicht. entsprechend sperren, entsorgen und aufheben; Wachs drauf, Wachs runter; Einatmen Ausatmen; und für alles andere sage ich: Wenn es sich gut anfühlt, mach es. Ihr Kilometerstand kann variieren ... wie es sollte ...
quelle
Ich denke, etwas auf Null zurückzusetzen ist chaotisch. Stellen Sie sich ein Szenario vor, in dem das jetzt festgelegte Element beispielsweise über die Eigenschaft verfügbar gemacht wird. Wenn ein Teil des Codes diese Eigenschaft versehentlich verwendet, nachdem das Element entsorgt wurde, erhalten Sie eine Nullreferenzausnahme, die einige Untersuchungen erfordert, um genau herauszufinden, was vor sich geht.
Ich glaube, dass Framework-Einwegartikel das Auslösen von ObjectDisposedException ermöglichen, was aussagekräftiger ist. Wenn Sie diese nicht auf Null zurücksetzen, ist dies aus diesem Grund besser.
quelle
Einige Objekte nehmen die
.dispose()
Methode an, mit der die Ressource aus dem Speicher entfernt wird.quelle