Wie ich verstehe, enthält der Stapelspeicher in Java Primitive und Methodenaufrufe, und der Heapspeicher wird zum Speichern von Objekten verwendet.
Angenommen, ich habe eine Klasse
class A {
int a ;
String b;
//getters and setters
}
Wo wird das Primitiv
a
in der KlasseA
aufbewahrt?Warum gibt es überhaupt Heapspeicher? Warum können wir nicht alles auf dem Stapel speichern?
Wenn das Objekt Müll sammelt, wird der dem Objekt zugeordnete Stapel zerstört?
Antworten:
Der grundlegende Unterschied zwischen Stack und Heap ist der Lebenszyklus der Werte.
Stapelwerte existieren nur im Rahmen der Funktion, in der sie erstellt wurden. Sobald sie zurückgegeben werden, werden sie verworfen.
Auf dem Heap sind jedoch Heap-Werte vorhanden. Sie werden zu einem bestimmten Zeitpunkt erstellt und zu einem anderen Zeitpunkt zerstört (entweder durch GC oder manuell, je nach Sprache / Laufzeit).
Jetzt speichert Java nur noch Primitive auf dem Stack. Dies hält den Stapel klein und hilft dabei, einzelne Stapelrahmen klein zu halten, wodurch mehr verschachtelte Aufrufe möglich sind.
Objekte werden auf dem Heap erstellt, und nur Verweise (die wiederum Grundelemente sind) werden auf dem Stapel herumgereicht.
Wenn Sie also ein Objekt erstellen, wird es mit allen dazugehörigen Variablen auf den Heap gelegt, damit es nach der Rückkehr des Funktionsaufrufs bestehen bleibt.
quelle
char
s sind Zahlen und können als solche synonym verwendet werden. Referenzen sind auch nur Zahlen, die sich auf eine Speicheradresse beziehen, die entweder 32 oder 64 Bit lang ist (obwohl sie nicht als solche verwendet werden können - es sei denn, Sie spielen herumsun.misc.Unsafe
).boolean
,byte
,short
,char
,int
,long
,float
Unddouble
.)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 :
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:
Wenn Sie also Code haben, der so aussieht:
wo das
...
nicht zulässtqux
, 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:
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.
quelle
quelle
Auf dem Heap, es sei denn, Java weist die Klasseninstanz auf dem Stack als Optimierung zu, nachdem mittels Escape-Analyse nachgewiesen wurde, dass dies keine Auswirkungen auf die Semantik hat. Dies ist jedoch ein Implementierungsdetail, sodass für alle praktischen Zwecke mit Ausnahme der Mikrooptimierung die Antwort "auf dem Haufen" lautet.
Der Stapelspeicher muss in der Reihenfolge des letzten Vorgangs zugewiesen und freigegeben werden. Der Heapspeicher kann in beliebiger Reihenfolge zugewiesen und freigegeben werden.
Wenn es sich bei dem Objekt um eine Garbage-Collection handelt, gibt es keine Referenzen mehr, die vom Stapel darauf verweisen. Wäre dies der Fall, würden sie das Objekt am Leben erhalten. Stapelprimitive werden überhaupt nicht mit Müll gesammelt, da sie automatisch zerstört werden, wenn die Funktion zurückkehrt.
quelle
Im Stapelspeicher werden lokale Variablen und Funktionsaufrufe gespeichert.
Während Heap-Speicher verwendet wird, um Objekte in Java zu speichern. Egal, wo das Objekt im Code erstellt wird.
In diesem Fall ist das Grundelement a einem Objekt der Klasse A zugeordnet. Es wird also im Heapspeicher erstellt.
Der Garbage Collector arbeitet im Bereich des Heap-Speichers, sodass Objekte, die keine Referenzkette haben, vom Stammverzeichnis gelöscht werden.
quelle
Zum besseren Verständnis (Heap / Stack-Speicher):
quelle