Frage

Sollten Sie alle Objekte auf setzen null (Nothing in VB.NET), sobald Sie damit fertig sind?

Ich verstehe, dass es in .NET wichtig ist, alle Instanzen von Objekten zu entfernen, die das implementieren IDisposable Schnittstelle, um einige Ressourcen freizugeben, obwohl das Objekt nach seiner Entsorgung immer noch etwas sein kann (daher die isDisposed Eigenschaft in Formularen), also gehe ich davon aus, dass sie noch im Speicher oder zumindest teilweise vorhanden sein kann?

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 werde ich es so einstellen null Beschleunigen Sie das System, indem Sie den Speicher freigeben, da es nicht herausfinden muss, dass er nicht mehr im Umfang enthalten ist. Gibt es irgendwelche schlimmen Nebenwirkungen?

MSDN -Artikel tun dies in Beispielen nie und derzeit mache ich dies, da ich den Schaden nicht sehen kann.Da ich jedoch auf unterschiedliche Meinungen gestoßen bin, sind Kommentare hilfreich.

War es hilfreich?

Lösung

Karl hat absolut Recht, es ist nicht nötig, Objekte nach der Verwendung auf Null zu setzen.Wenn ein Objekt implementiert IDisposable, rufen Sie einfach an IDisposable.Dispose() wenn Sie mit diesem Objekt fertig sind (eingewickelt in ein try..finally, oder ein using() Block).Aber auch wenn Sie nicht daran denken, anzurufen Dispose(), sollte die Finalizer-Methode für das Objekt aufgerufen werden Dispose() für dich.

Ich dachte, das wäre eine gute Behandlung:

Eintauchen in IDisposable

und das

IDisposable verstehen

Es macht keinen Sinn, den GC und seine Managementstrategien hinterfragen zu wollen, weil er selbstoptimierend und undurchsichtig ist.Eine gute Diskussion über das Innenleben mit Jeffrey Richter bei Dot Net Rocks gab es hier: Jeffrey Richter über das Windows-Speichermodell und Richter Buch CLR über C# Kapitel 20 enthält eine großartige Behandlung:

Andere Tipps

Ein weiterer Grund, Objekte nicht auf null zu setzen, wenn Sie mit ihnen fertig sind, besteht darin, dass sie dadurch tatsächlich länger am Leben bleiben können.

z.B.

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is now eligible for garbage collection         

    // ... rest of method not using 'someType' ...
}

ermöglicht, dass das von someType referenzierte Objekt nach dem Aufruf von „DoSomething“ einer GC unterzogen wird

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is NOT eligible for garbage collection yet
    // because that variable is used at the end of the method         

    // ... rest of method not using 'someType' ...
    someType = null;
}

kann manchmal das Objekt bis zum Ende der Methode am Leben halten.Der JIT optimiert normalerweise die Zuweisung auf Null, sodass beide Codebits am Ende gleich sind.

Nein, Objekte nicht auf Null setzen.Sie können auschecken http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx Weitere Informationen finden Sie hier. Wenn Sie die Dinge jedoch auf Null setzen, wird dies nichts bewirken, außer Ihren Code zu verfälschen.

Auch:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

Im Allgemeinen besteht keine Notwendigkeit, Objekte nach der Verwendung auf Null zu setzen, aber in manchen Fällen halte ich es für eine gute Vorgehensweise.

Wenn ein Objekt IDisposable implementiert und in einem Feld gespeichert ist, ist es meiner Meinung nach sinnvoll, es auf Null zu setzen, nur um die Verwendung des entsorgten Objekts zu vermeiden.Die Fehler der folgenden Art können schmerzhaft sein:

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();

Es ist sinnvoll, das Feld nach der Entsorgung auf Null zu setzen und direkt an der Zeile, in der das Feld erneut verwendet wird, einen NullPtrEx zu erhalten.Andernfalls könnten Sie später auf einen kryptischen Fehler stoßen (abhängig davon, was genau DoSomething tut).

Es besteht die Möglichkeit, dass Ihr Code nicht streng genug strukturiert ist, wenn Sie das für nötig halten null Variablen.

Es gibt verschiedene Möglichkeiten, den Gültigkeitsbereich einer Variablen einzuschränken:

Wie erwähnt von Steve Tranby

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

Ebenso können Sie einfach geschweifte Klammern verwenden:

{
    // Declare the variable and use it
    SomeObject object = new SomeObject()
}
// The variable is no longer available

Ich finde, dass die Verwendung von geschweiften Klammern ohne „Überschrift“ den Code wirklich bereinigt und verständlicher macht.

Sie sollten eine Variable nur dann auf Null setzen, wenn die Variable ihren Gültigkeitsbereich nicht verlässt und Sie die damit verbundenen Daten nicht mehr benötigen.Ansonsten besteht keine Notwendigkeit.

Im Allgemeinen ist es nicht erforderlich, den Wert auf null zu setzen.Angenommen, Sie haben in Ihrer Klasse eine Reset-Funktion.

Dann könnten Sie dies tun, da Sie dispose nicht zweimal aufrufen möchten, da einige der Dispose-Anweisungen möglicherweise nicht korrekt implementiert sind und eine System.ObjectDisposed-Ausnahme auslösen.

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }

Diese Art von „Es besteht keine Notwendigkeit, Objekte nach der Verwendung auf Null zu setzen“ ist nicht ganz korrekt.Es kann vorkommen, dass Sie die Variable nach der Entsorgung auf NULL setzen müssen.

Ja, Sie sollten IMMER anrufen .Dispose() oder .Close() auf alles, was es hat, wenn Sie fertig sind.Seien es Dateihandles, Datenbankverbindungen oder Wegwerfobjekte.

Davon abgesehen ist das sehr praktische Muster von LazyLoad.

Angenommen, ich habe und instanziiert ObjA von class A. Class A hat ein öffentliches Eigentum namens PropB von class B.

Im Inneren, PropB verwendet die private Variable von _B und ist standardmäßig null.Wann PropB.Get() verwendet wird, prüft es, ob _PropB ist null und wenn ja, werden die Ressourcen geöffnet, die zum Instanziieren von a erforderlich sind B hinein _PropB.Dann kehrt es zurück _PropB.

Meiner Erfahrung nach ist das ein wirklich nützlicher Trick.

Die Notwendigkeit, den Wert auf Null zu setzen, besteht dann, wenn Sie A zurücksetzen oder auf irgendeine Weise ändern, die den Inhalt von A beeinträchtigt _PropB waren das untergeordnete Element der vorherigen Werte von A, müssen Sie entsorgen UND auf Null setzen _PropB So kann LazyLoad zurückgesetzt werden, um den richtigen Wert abzurufen, WENN der Code dies erfordert.

Wenn du es nur tust _PropB.Dispose() Und kurz nachdem Sie davon ausgehen, dass die Nullprüfung für LazyLoad erfolgreich ist, wird sie nicht null sein und Sie werden veraltete Daten sehen.Tatsächlich müssen Sie es danach auf Null setzen Dispose() Nur um sicher zu gehen.

Ich wünschte wirklich, es wäre anders, aber ich habe gerade Code, der dieses Verhalten nach einer Weile zeigt Dispose() auf einen _PropB und außerhalb der aufrufenden Funktion, die das Dispose durchgeführt hat (und damit fast außerhalb des Gültigkeitsbereichs), ist die private Requisite immer noch nicht null und die veralteten Daten sind immer noch vorhanden.

Letztendlich wird die entsorgte Eigenschaft auf Null gesetzt, aber das war aus meiner Sicht nicht deterministisch.

Der Hauptgrund ist, wie dbkk andeutet, dass der übergeordnete Container (ObjA mit PropB) behält die Instanz von _PropB im Umfang, trotz der Dispose().

In einigen Fällen ist es sinnvoll, Referenzen auf Null zu setzen.Wenn Sie beispielsweise eine Sammlung schreiben – etwa eine Prioritätswarteschlange –, sollten Sie diese Objekte laut Vertrag nicht für den Client 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 übersteht, ist das viel weniger wichtig.

Im Großen und Ganzen sollte man sich die Mühe wirklich nicht machen.Lassen Sie den Compiler und den GC ihre Aufgaben erledigen, damit Sie Ihre Aufgaben erledigen können.

Schauen Sie sich auch diesen Artikel an: http://www.codeproject.com/KB/cs/idisposable.aspx

In den meisten Fällen hat das Setzen eines Objekts auf Null keine Auswirkung.Sie sollten dies nur dann unbedingt tun, wenn Sie mit einem „großen Objekt“ arbeiten, das größer als 84 KB ist (z. B. Bitmaps).

Stephen Cleary erklärt es in diesem Beitrag sehr gut: Sollte ich Variablen auf Null setzen, um die Garbage Collection zu unterstützen?

Sagt:

Die kurze Antwort für das ungeduldige Ja, wenn die Variable ein statisches Feld ist oder wenn Sie eine aufzählbare Methode (unter Verwendung der Ertragsrendite) oder eine asynchrone Methode (unter Verwendung von Async und Warted) schreiben.Ansonsten nein.

Das bedeutet, dass Sie in regulären Methoden (nicht aufzählbar und nicht asynchron) keine lokalen Variablen, Methodenparameter oder Instanzfelder auf Null setzen.

(Auch wenn Sie IDisposable.Dispose implementieren, sollten Sie Variablen nicht auf Null setzen.)

Das Wichtigste, was wir berücksichtigen sollten, ist Statische Felder.

Statische Felder sind immer Stammobjekte, also sind sie immer als „lebendig“ betrachtet durch den Müllsammler.Wenn ein statisches Feld auf ein Objekt verweist, das nicht mehr benötigt wird, sollte es auf null gesetzt werden, damit der Garbage Collector es als für die Sammlung geeignet behandelt.

Das Festlegen statischer Felder auf Null ist bedeutungslos, wenn der gesamte Prozess heruntergefahren wird.Zu diesem Zeitpunkt wird der gesamte Heap, einschließlich aller Root-Objekte, durch Müll gesammelt.

Abschluss:

Statische Felder;das ist alles.Alles andere ist ein Zeitverschwendung.

Ich glaube, dass dies aufgrund der GC-Implementierer nicht möglich ist beschleunigen GC mit Aufhebung.Ich bin mir sicher, dass es ihnen lieber wäre, wenn Sie sich keine Gedanken darüber machen würden, wie/wann GC läuft – behandeln Sie es so, dass es allgegenwärtig ist Sein beschütze und wache immer und überall für dich ... (beugt den Kopf nach unten, hebt die Faust in den Himmel) ...

Persönlich setze ich Variablen oft explizit auf null, wenn ich mit ihnen fertig bin, als eine Form der Selbstdokumentation.Ich deklariere, verwende und setze sie später nicht auf null – ich setze sie sofort auf null, wenn 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 notwendig?NEIN.Ist es hilfreich für den GC?Vielleicht ja, vielleicht nein, ich weiß es nicht genau, ich kann es konstruktionsbedingt 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 das Nulling optimiert ist, ist das kaum mehr als eine Fantasie Kommentar wenn du möchtest.

Ich frage mich, ob es dem nächsten armen Narren, der in meine Fußstapfen tritt, meine Absicht klarer macht, und wenn ja "könnte" Vielleicht hilft GC manchmal, dann lohnt es sich für mich.Meistens fühle ich mich dadurch aufgeräumt und klar, und Mongo fühlt sich gerne aufgeräumt und klar.:) :)

Ich sehe es so:Es gibt Programmiersprachen, die es Menschen ermöglichen, anderen Menschen eine Vorstellung von der Absicht zu geben und einem Compiler eine Jobanfrage zu geben, was zu tun ist – der Compiler konvertiert diese Anfrage in eine andere Sprache (manchmal mehrere) für eine CPU – die die CPU(s) geben könnte Ein Scherz, welche Sprache Sie verwendet haben, Ihre Tab-Einstellungen, Kommentare, stilistische Schwerpunkte, Variablennamen usw.– Bei einer CPU dreht sich alles um den Bitstrom, der ihr mitteilt, welche Register, Opcodes und Speicherorte bearbeitet werden müssen.Viele im Code geschriebene Dinge werden nicht in der von uns angegebenen Reihenfolge in das umgewandelt, was von der CPU verbraucht wird.Unser C, C++, C#, Lisp, Babel, Assembler oder was auch immer ist eher Theorie als Realität, geschrieben als Arbeitserklärung.Was Sie sehen, ist nicht das, was Sie bekommen, ja, nicht einmal in Assembler-Sprache.

Ich verstehe, dass die Denkweise "unnötige Dinge" (wie leere Zeilen) nichts anderes als Geräusche und Code sind. " Das war ich früher in meiner Karriere;Das verstehe ich vollkommen.An dieser Stelle tendiere ich zu dem, was den Code klarer macht.Es ist nicht so, dass ich meinen Programmen auch nur 50 Zeilen „Rauschen“ hinzufüge – es sind hier oder da ein paar Zeilen.

Von jeder Regel gibt es Ausnahmen.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 Ihr eigenes Gedächtnis verwalten und entsprechend sperren und aufheben, da das Gedächtnis nicht Teil des GC-Universums ist – hoffentlich versteht das jeder.In der restlichen Zeit ist es bei GC-basierten Sprachen 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.ordnungsgemäß sperren, entsorgen und ungültig machen;Wachs drauf, Wachs runter;Einatmen Ausatmen;und für alles andere sage ich:Wenn es sich gut anfühlt, dann tu es.Ihr Kilometerstand kann variieren ... wie es sollte ...

Einige Objekte nehmen an, dass dies der Fall ist .dispose() Methode, die das Entfernen der Ressource aus dem Speicher erzwingt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top