Ok, ich verstehe den Stack und den Heap (Werte leben auf dem Stack, Referenzen auf dem Heap).
Wenn ich eine neue Instanz einer Klasse deklariere, befindet sich diese auf dem Heap mit einem Verweis auf diesen Punkt im Speicher des Stapels. Ich weiß auch, dass C # eine eigene Garbage Collection hat (dh es bestimmt, wann eine instanziierte Klasse nicht mehr verwendet wird und den Speicher zurückfordert).
Ich habe 2 Fragen:
Ich frage, weil ich eine Methode in einer For-Schleife habe. Jedes Mal, wenn ich eine Schleife durchlaufe, erstelle ich eine neue Instanz meiner Klasse. In meinem Kopf visualisiere ich all diese Klassen, die auf einem Haufen herumliegen und nichts tun, als die Erinnerung aufzunehmen, und ich möchte sie so schnell wie möglich loswerden, um die Dinge sauber und ordentlich zu halten!
Verstehe ich das richtig oder verpasse ich etwas?
Ok, ich verstehe den Stack und den Heap (Werte leben auf dem Stack, Referenzen auf dem Heap
Ich glaube nicht, dass Sie den Stapel und den Haufen verstehen. Wenn Werte auf dem Stack leben, wo lebt dann ein Array von ganzen Zahlen? Ganzzahlen sind Werte. Erzählst du mir, dass ein Array von ganzen Zahlen seine ganzen Zahlen auf dem Stapel hält? Wenn Sie beispielsweise ein Array von ganzen Zahlen von einer Methode mit zehntausend ganzen Zahlen zurückgeben, sagen Sie mir, dass diese zehntausend ganzen Zahlen auf den Stapel kopiert werden?
Werte leben auf dem Stapel, wenn sie auf dem Stapel leben, und leben auf dem Haufen, wenn sie auf dem Haufen leben. Die Idee, dass der Typ einer Sache mit der Lebensdauer ihres Speichers zu tun hat, ist Unsinn. Speicherorte, die kurzlebig sind gehen auf den Stapel; Speicherorte, die langlebig sind gehen auf den Heap, und zwar unabhängig von ihrem Typ. Ein langlebiger Int muss auf dem Heap abgelegt werden, genau wie eine langlebige Instanz einer Klasse.
Wenn ich eine neue Instanz einer Klasse deklariere, lebt diese auf dem Heap mit einem Verweis auf diesen Punkt im Speicher des Stacks.
Warum muss die Referenz auf den Stapel gelegt werden? Auch hier hat die Lebensdauer der Speicherung der Referenz nichts mit ihrem Typ zu tun . Wenn der Speicher der Referenz langlebig ist, geht die Referenz auf den Heap.
Ich weiß auch, dass C # eine eigene Garbage Collection hat (dh es bestimmt, wann eine instanziierte Klasse nicht mehr verwendet wird und den Speicher zurückfordert).
Die C # -Sprache tut dies nicht; die CLR tut das.
Ist mein Verständnis von Garbage Collection korrekt?
Sie scheinen eine Menge Lügen über den Stapel und den Haufen zu glauben, also sind die Chancen gut, nein, das ist es nicht.
Kann ich meine eigenen machen?
Nicht in C #, nein.
Ich frage, weil ich eine Methode in einer For-Schleife habe. Jedes Mal, wenn ich eine Schleife durchlaufe, erstelle ich eine neue Instanz meiner Klasse. In meinem Kopf visualisiere ich all diese Klassen, die auf einem Haufen herumliegen und nichts tun, als die Erinnerung aufzunehmen, und ich möchte sie so schnell wie möglich loswerden, um die Dinge sauber und ordentlich zu halten!
Der Sinn von Garbage Collection liegt darin, Sie von der Aufräumaktion zu befreien. Deshalb heißt es "automatische Garbage Collection". Es räumt für dich.
Wenn Sie befürchten, dass Ihre Schleifen Sammeldruck erzeugen und Sie den Sammlungsdruck aus Leistungsgründen vermeiden möchten, rate ich Ihnen, eine Pooling Strategie zu verfolgen. Es wäre ratsam, mit einer expliziten Pooling-Strategie zu beginnen; das ist:
%Vor%anstatt zu versuchen, automatisches Pooling mit einem wiederbelebenden Finalizer durchzuführen. Ich rate generell von Finalizern und der Auferstehung von Objekten ab, es sei denn, Sie sind ein Experte für Finalisierungssemantik.
Der Pool weist natürlich einen neuen Frob zu, wenn es keinen im Pool gibt. Wenn es einen im Pool gibt, dann gibt er es aus und entfernt es aus dem Pool, bis es wieder eingesetzt wird. (Wenn Sie vergessen, einen Frob zurück in den Pool zu legen, wird der GC ihn schließlich erreichen.) Indem Sie verfolgen Eine Pooling-Strategie, die Sie veranlassen, dass der GC schließlich alle Frobs auf den Heap der Generation 2 verschiebt, anstatt im Heap der Generation 0 viel Sammlungsdruck zu erzeugen. Der Sammeldruck verschwindet dann, weil keine neuen Frobs zugeordnet sind. Wenn etwas anderes Sammlungsdruck produziert, sind die Frobs alle sicher im Gen 2 Haufen, wo sie selten besucht werden.
Dies ist natürlich das genaue Gegenteil der von Ihnen beschriebenen Strategie; Der springende Punkt der Pooling-Strategie besteht darin, dass Objekte auf ewig blockiert werden. Objekte, die für immer herumhängen, sind eine gute Sache, wenn Sie sie benutzen wollen.
Machen Sie diese Art von Änderungen natürlich nicht, bevor Sie per Profiling wissen, dass Sie aufgrund des Sammeldrucks ein Performance-Problem haben! Es ist selten, dass ein solches Problem auf der Desktop-CLR auftritt. es ist eher üblich auf der kompakten CLR.
Ganz allgemein, wenn Sie die Art von Person sind, die sich unwohl fühlt, wenn ein Speichermanager für Sie nach seinem Zeitplan aufräumt, dann ist C # nicht die richtige Sprache für Sie. Betrachten Sie stattdessen C.
Werte leben auf dem Stack, Referenzen auf dem Heap
Dies ist ein Implementierungsdetail . Es gibt nichts, was ein .NET Framework daran hindern könnte, beides auf dem Stack zu speichern.
Ich weiß auch, dass C # eine eigene Garbage Collection hat
C # hat damit nichts zu tun. Dies ist ein Service der CLR. VB.NET, F # usw. haben immer noch eine Garbage-Collection.
Die CLR wird ein Objekt aus dem Speicher entfernen, wenn es keine starken Wurzeln hat. Zum Beispiel, wenn Ihre Klasseninstanz den Geltungsbereich in Ihrer for-Schleife verlässt. Es wird ein paar herumliegen, aber sie werden schließlich gesammelt, entweder durch Garbage Collection oder das Programm beendet werden.
Kann ich meine eigenen machen? Wenn ja, gibt es einen wirklichen Vorteil, dies selbst zu tun oder sollte ich es einfach verlassen?
Sie können GC.Collect
verwenden, um eine Sammlung zu erzwingen. Sie sollten es nicht tun, weil es eine teure Operation ist. Teurer, als ein paar Objekte den Speicher etwas länger zu belegen, als sie unbedingt benötigt werden. Der GC ist unglaublich gut in dem, was er alleine macht. Sie werden auch kurzlebige Objekte zwingen, Generationen zu fördern, die sie normalerweise nicht bekommen würden.
Zunächst zu Erics bahnbrechendem Beitrag über Die Wahrheit über Werttypen
Zweitens, bei der Garbage-Collection weiß der Collector weit mehr über Ihr laufendes Programm als Sie, versuchen Sie nicht, es zu erraten, es sei denn, Sie befinden sich in der unglaublich unwahrscheinlichen Situation, in der Sie einen Speicher haben Leck.
Also zu Ihrer zweiten Frage, nein, versuchen Sie nicht, dem GC zu "helfen".
Ich werde einen Beitrag zu diesem Effekt auf dem CG finden und diese Antwort aktualisieren.
Kann ich meine eigenen machen? Wenn ja, gibt es einen wirklichen Vorteil, dies selbst zu tun, oder sollte ich es einfach verlassen.
Ja, Sie können mit GC.Collect
, aber Sie sollten nicht . Der GC ist für kurzlebige Variablen, solche in einer Methode und langlebige Variablen optimiert, die normalerweise für die gesamte Lebensdauer der Anwendung gültig bleiben.
Variablen, die dazwischen liegen, sind nicht so gebräuchlich und nicht wirklich optimal für den GC.
Wenn Sie ein GC.Collect-Objekt erzwingen, werden Sie eher dazu führen, dass Variablen im Gültigkeitsbereich in diesen Zwischenzustand gezwungen werden, was das Gegenteil von dem ist, was Sie erreichen möchten.
Auch aus dem MSDN-Artikel High-Performance Managed Applications schreiben: Eine Fibel
>Der GC stimmt sich selbst ab und passt sich den Anwendungen an Speicheranforderungen. In den meisten Fällen wird ein GC programmgesteuert aufgerufen behindern diese Abstimmung. "Helfen" den GC durch den Aufruf von GC.Collect wird mehr als wahrscheinlich nicht verbessern die Leistung Ihrer Anwendungen
Ihr Verständnis von Garbage Collection ist gut genug. Im Wesentlichen gilt eine nicht referenzierte Instanz als außerhalb des Bereichs und wird nicht mehr benötigt. Nachdem dies festgestellt wurde, entfernt der Kollektor ein nicht referenziertes Objekt an einem zukünftigen Punkt.
Es gibt keine Möglichkeit, den Garbage Collector dazu zu zwingen, nur eine bestimmte Instanz zu sammeln. Sie können ihn bitten, seine normale Operation "collect everything possible" GC.Collect()
auszuführen, aber Sie sollten nicht. Der Müllsammler ist effizient und effektiv, wenn Sie es sich selbst überlassen.
Besonders hervorzuheben ist das Sammeln von Objekten, die eine kurze Lebensdauer haben, genau wie solche, die als temporäre Objekte erstellt werden. Sie sollten sich keine Gedanken darüber machen müssen, wie viele Objekte in einer Schleife erstellt werden, es sei denn, sie haben eine lange Lebensdauer, die eine sofortige Erfassung verhindert.
Bitte lesen Sie verwandte Fragen in Bezug auf die Stapel und Haufen.
Wenn Sie in Ihrem spezifischen Szenario zustimmen, dass Objekte in einer For-Schleife neu erstellt werden, haben Sie eine suboptimale Leistung. Werden die Objekte in der Schleife gespeichert (oder anderweitig verwendet) oder werden sie verworfen? Wenn letzteres möglich ist, können Sie dies optimieren, indem Sie ein Objekt außerhalb der Schleife neu erstellen und wiederverwenden?
Wenn Sie Ihren eigenen GC implementieren möchten, gibt es in C # kein explizites Lösch-Schlüsselwort, Sie müssen es der CLR überlassen. Sie können jedoch Hinweise geben, wie zum Beispiel wann Sie etwas sammeln oder was Sie während der Sammlung ignorieren sollten.
Mit freundlichen Grüßen
Lesen Sie den folgenden Artikel von Microsoft, um ein Wissen über Garbage Collection in C # zu erlangen. Ich bin mir sicher, dass es jedem helfen wird, der Informationen in dieser Angelegenheit benötigt.
Speicherverwaltung und Speicherbereinigung im .NET Framework
Wenn Sie beim Schreiben von C # an der Leistung einiger Bereiche in Ihrem Code interessiert sind, können Sie unsicherer Code . Sie werden ein Plus an Leistung haben, und in Ihrem festen Block wird der Müllsammler höchstwahrscheinlich nicht auftreten.
Garbage Collection ist im Grunde Referenz-Tracking. Ich kann mir keinen guten Grund vorstellen, warum Sie es ändern wollen. Haben Sie ein Problem, bei dem Sie feststellen, dass Speicher nicht freigegeben wird? Oder Sie suchen nach dem Disposemuster
Bearbeiten: "Reference Counting" wurde durch "Reference Tracking" ersetzt, um nicht mit dem Increment / Decrement Counter des Objekts Reference / Dereference (zB von Python) verwechselt zu werden. Ich dachte, es wäre ziemlich üblich, die Objektgraph-Generierung wie in dieser Antwort als "Zählen" zu bezeichnen: Warum keine Referenzzählung + Garbage Collection in C #? Aber ich werde den Handschuh von Eric Lippert nicht aufnehmen:)