Wo werden primitive Felder gespeichert?
Primitive Felder werden als Teil des Objekts gespeichert, das irgendwo instanziiert wird . Der einfachste Weg, sich vorzustellen, wo dies ist, ist der Haufen. Dies ist jedoch nicht immer der Fall. Wie in Java-Theorie und -Praxis beschrieben: Legenden zur urbanen Performance, überarbeitet :
JVMs können eine Technik namens Escape-Analyse verwenden, mit der sie feststellen können, dass bestimmte Objekte während ihrer gesamten Lebensdauer auf einen einzelnen Thread beschränkt bleiben und dass die Lebensdauer durch die Lebensdauer eines bestimmten Stack-Frames begrenzt ist. Solche Objekte können sicher auf dem Stapel anstelle des Heaps zugeordnet werden. Noch besser ist, dass die JVM für kleine Objekte die Zuordnung vollständig optimieren und die Felder des Objekts einfach in Register hochziehen kann.
Somit kann man nicht sagen, dass "das Objekt erstellt wurde und das Feld auch vorhanden ist", sondern ob sich etwas auf dem Haufen oder auf dem Stapel befindet. Beachten Sie, dass es bei kleinen, kurzlebigen Objekten möglich ist, dass das 'Objekt' nicht als solches im Speicher vorhanden ist und stattdessen die Felder direkt in Registern abgelegt werden.
Das Papier schließt mit:
JVMs sind erstaunlich gut darin, Dinge herauszufinden, von denen wir bisher angenommen haben, dass nur der Entwickler sie wissen könnte. Wenn die JVM von Fall zu Fall zwischen Stapelzuweisung und Heapzuweisung wählen kann, können wir die Leistungsvorteile der Stapelzuweisung nutzen, ohne dass sich der Programmierer darüber ärgert, ob auf dem Stapel oder auf dem Heap zuzuweisen ist.
Wenn Sie also Code haben, der so aussieht:
void foo(int arg) {
Bar qux = new Bar(arg);
...
}
wo das ...
nicht zulässt qux
, diesen Bereich zu verlassen, qux
kann stattdessen auf dem Stapel zugewiesen werden. Dies ist tatsächlich ein Gewinn für die VM, da dies bedeutet, dass niemals Müll eingesammelt werden muss - er verschwindet, wenn er den Gültigkeitsbereich verlässt.
Mehr zur Fluchtanalyse bei Wikipedia. Für diejenigen, die bereit sind, sich mit Artikeln zu beschäftigen, bietet Escape Analysis für Java von IBM. Für diejenigen, die aus einer C # -Welt kommen, ist The Stack ein Implementierungsdetail und die Wahrheit über Werttypen von Eric Lippert eine gute Lektüre (sie sind auch für Java-Typen nützlich, da viele der Konzepte und Aspekte gleich oder ähnlich sind). . Warum geht es in .Net-Büchern um die Zuordnung von Stapel- und Heapspeicher? geht auch darauf ein.
Auf dem Wieso des Stapels und des Haufens
Auf dem Haufen
Warum also überhaupt den Stapel oder den Haufen? Für Dinge, die den Spielraum verlassen, kann der Stapel teuer sein. Betrachten Sie den Code:
void foo(String arg) {
bar(arg);
...
}
void bar(String arg) {
qux(arg);
...
}
void qux(String arg) {
...
}
Die Parameter sind ebenfalls Teil des Stacks. In der Situation, dass Sie keinen Heap haben, übergeben Sie den vollständigen Satz von Werten auf dem Stapel. Dies ist in Ordnung für "foo"
und kleine Zeichenfolgen ... aber was würde passieren, wenn jemand eine große XML-Datei in diese Zeichenfolge einfügen würde. Jeder Aufruf würde die gesamte riesige Zeichenfolge auf den Stapel kopieren - und das wäre ziemlich verschwenderisch.
Stattdessen ist es besser, die Objekte, deren Leben außerhalb des unmittelbaren Bereichs liegt (an einen anderen Bereich übergeben, in einer von einem anderen verwalteten Struktur festgehalten, usw.), in einen anderen Bereich zu verschieben, der als Haufen bezeichnet wird.
Auf dem Stapel
Sie brauchen den Stapel nicht. Man könnte hypothetisch eine Sprache schreiben, die keinen Stapel (von beliebiger Tiefe) verwendet. Ein altes BASIC, auf dem ich in meiner Jugend gelernt habe, hat dies getan, man konnte nur 8 Ebenen von gosub
Aufrufen ausführen und alle Variablen waren global - es gab keinen Stapel.
Der Vorteil des Stapels besteht darin, dass bei Verwendung einer Variablen, die mit einem Bereich existiert, beim Verlassen dieses Bereichs dieser Stapelrahmen eingeblendet wird. Es vereinfacht wirklich, was da ist und was nicht. Das Programm wechselt zu einer anderen Prozedur, einem neuen Stapelrahmen. Das Programm kehrt zur Prozedur zurück, und Sie befinden sich wieder in dem Bereich, in dem Ihr aktueller Bereich angezeigt wird. Das Programm verlässt die Prozedur und alle Elemente auf dem Stapel werden freigegeben.
Dies erleichtert der Person das Schreiben der Laufzeit für den Code, um einen Stapel und einen Haufen zu verwenden. Sie sind einfach viele Konzepte und Arbeitsweisen am Code, die es der Person, die den Code in der Sprache schreibt, ermöglichen, sich frei zu machen, explizit an sie zu denken.
Die Natur des Stapels bedeutet auch, dass er nicht fragmentiert werden kann. Speicherfragmentierung ist ein echtes Problem mit dem Heap. Sie ordnen ein paar Objekte zu, sammeln dann ein mittleres und versuchen dann, Platz für das nächste große Objekt zu finden, das zugewiesen werden soll. Es ist ein Chaos. In der Lage zu sein, Dinge auf den Stapel zu legen, bedeutet, dass Sie sich nicht darum kümmern müssen.
Wenn etwas Müll gesammelt wird
Wenn etwas Müll ist, ist es weg. Aber es wird nur Müll gesammelt, weil es bereits vergessen wurde - es gibt keine Referenzen mehr auf das Objekt im Programm, auf die vom aktuellen Status des Programms aus zugegriffen werden kann.
Ich werde darauf hinweisen, dass dies eine sehr große Vereinfachung der Speicherbereinigung ist. Es gibt viele Garbage Collectors (sogar in Java - Sie können den Garbage Collector mithilfe verschiedener Flags ( Dokumente ) optimieren . Diese verhalten sich unterschiedlich und die Nuancen der einzelnen Aktionen sind für diese Antwort etwas zu tief. Sie möchten möglicherweise lesen Grundlagen der Java Garbage Collection , um eine bessere Vorstellung davon zu bekommen, wie ein Teil davon funktioniert.
Das heißt, wenn etwas auf dem Stapel zugewiesen ist, wird es nicht als Teil von Garbage System.gc()
Collected freigegeben, wenn der Stapelrahmen aufspringt. Wenn sich etwas auf dem Haufen befindet und von etwas auf dem Stapel referenziert wird, wird zu diesem Zeitpunkt kein Müll gesammelt.
Warum ist das wichtig?
Zum größten Teil seine Tradition. Die geschriebenen Lehrbücher und Compiler-Klassen sowie die verschiedenen Bit-Dokumentationen machen eine große Sache über den Haufen und den Stapel.
Die heutigen virtuellen Maschinen (JVM und ähnliche) haben jedoch große Anstrengungen unternommen, um dies vor dem Programmierer zu verbergen. Es spielt keine große Rolle, es sei denn, Sie haben das eine oder andere Problem und müssen wissen, warum (anstatt nur den Speicherplatz entsprechend zu vergrößern).
Das Objekt befindet sich irgendwo und seine in dem Ort , wo es richtig und schnell für die entsprechende Menge an Zeit zugegriffen werden kann , dass es existiert. Ob auf dem Stapel oder auf dem Haufen - es spielt keine Rolle.