9412 Stimmen

Was ist der Stack und der Heap und wo befinden sie sich?

  • Was sind der Stack und der Heap?
  • Wo befinden sie sich physisch im Speicher eines Computers?
  • In welchem Maße werden sie vom Betriebssystem oder der Laufzeitumgebung der Sprache kontrolliert?
  • Was ist ihr Geltungsbereich?
  • Was bestimmt ihre Größen?
  • Was macht einen schneller?

5 Stimmen

@mattshane Die Definitionen von Stack und Heap hängen überhaupt nicht von Wert- und Referenztypen ab. Mit anderen Worten, der Stack und Heap können vollständig definiert werden, auch wenn Wert- und Referenztypen niemals existiert hätten. Darüber hinaus ist der Stack nur ein Implementierungsdetail beim Verständnis von Wert- und Referenztypen. Laut Eric Lippert: Der Stack ist ein Implementierungsdetail, Teil Eins.

248 Stimmen

Eine wirklich gute Erklärung finden Sie hier Was ist der Unterschied zwischen einem Stapel und einem Heap?

19 Stimmen

Auch (wirklich) gut: codeproject.com/Articles/76153/… (der Stack-/Heap-Teil)

6812voto

Jeff Hill Punkte 67726

Der Stack ist der Speicher, der als Zwischenspeicher für einen Ausführungsfaden reserviert ist. Wenn eine Funktion aufgerufen wird, wird ein Block am oberen Rand des Stacks für lokale Variablen und einige Buchungsinformationen reserviert. Wenn diese Funktion zurückkehrt, wird der Block ungenutzt und kann beim nächsten Funktionsaufruf verwendet werden. Der Stack wird immer in einer LIFO (Last In First Out)-Reihenfolge reserviert; der zuletzt reservierte Block ist immer der nächste, der freigegeben wird. Dies macht es wirklich einfach, den Stack zu verfolgen; das Freigeben eines Blocks aus dem Stack ist nichts weiter als die Anpassung eines Zeigers.

Der Heap ist Speicherplatz für die dynamische Zuweisung. Im Gegensatz zum Stack gibt es kein festgelegtes Muster für die Zuweisung und Freigabe von Blöcken aus dem Heap; Sie können einen Block jederzeit zuweisen und ihn jederzeit freigeben. Dies macht es viel komplexer, zu verfolgen, welche Teile des Heaps zu einem bestimmten Zeitpunkt zugewiesen oder frei sind; Es gibt viele benutzerdefinierte Heap-Allokatoren, die die Leistung des Heaps für unterschiedliche Verwendungsmuster optimieren.

Jeder Thread erhält einen Stack, während es in der Regel nur einen Heap für die Anwendung gibt (obwohl es nicht ungewöhnlich ist, mehrere Heaps für verschiedene Arten von Zuweisungen zu haben).

Um Ihre Fragen direkt zu beantworten:

Inwieweit werden sie vom Betriebssystem oder der Laufzeitumgebung der Sprache kontrolliert?

Das Betriebssystem reserviert den Stack für jeden System-Thread, wenn der Thread erstellt wird. Typischerweise wird das Betriebssystem von der Laufzeitumgebung der Sprache aufgerufen, um den Heap für die Anwendung zuzuweisen.

Was ist ihr Anwendungsbereich?

Der Stack ist an einen Thread gebunden, sodass der Stack zurückgewonnen wird, wenn der Thread beendet wird. Der Heap wird normalerweise beim Start der Anwendung von der Laufzeitumgebung zugeordnet und wird beim Beenden der Anwendung (technisch des Prozesses) zurückgewonnen.

Was bestimmt die Größe von jedem von ihnen?

Die Größe des Stacks wird bei der Erstellung eines Threads festgelegt. Die Größe des Heaps wird beim Start der Anwendung festgelegt, kann aber wachsen, wenn Platz benötigt wird (der Zuweiser fordert mehr Speicher vom Betriebssystem an).

Was macht einen schneller?

Der Stack ist schneller, weil das Zugriffsmuster es trivial macht, Speicher von ihm zuzuweisen und freizugeben (ein Zeiger/Ganzzahl wird einfach erhöht oder verringert), während im Heap viel komplexere Buchführung bei einer Zuweisung oder Freigabe involviert ist. Auch wird jedes Byte im Stack sehr häufig wiederverwendet, was bedeutet, dass es tendenziell in den Cache des Prozessors eingemischt wird, was es sehr schnell macht. Ein weiterer Performance-Nachteil für den Heap ist, dass der Heap, als meist globale Ressource, typischerweise mehrfädig sicher sein muss, d.h. jede Zuweisung und Freigabe muss - in der Regel - synchronisiert sein mit "allen" anderen Heap-Zugriffen im Programm.

Eine klare Demonstration:
Bildquelle: <a href="http://vikashazrati.wordpress.com/2007/10/01/quicktip-java-basics-stack-and-heap/" rel="noreferrer">vikashazrati.wordpress.com</a>

8 Stimmen

"Der Stapel ist der Speicherplatz, der als Zwischenspeicher vorgesehen ist". Cool. Aber wo wird er tatsächlich in Bezug auf die Java-Speicherstruktur "vorgesehen"?? Ist es Heap-Speicher/Nicht-Heap-Speicher/Andere (Java-Speicherstruktur gemäß betsol.com/2017/06/…)

140 Stimmen

Gute Antwort - aber ich denke, du solltest hinzufügen, dass der Stack vom Betriebssystem zugewiesen wird, wenn der Prozess startet (unter der Voraussetzung, dass ein Betriebssystem existiert), aber vom Programm inline verwaltet wird. Dies ist ein weiterer Grund, warum der Stack schneller ist - Push- und Pop-Operationen sind in der Regel eine Maschinenanweisung, und moderne Maschinen können mindestens 3 davon in einem Zyklus ausführen, während Allokieren oder Freigeben des Heap das Aufrufen von OS-Code involviert.

490 Stimmen

Ich bin wirklich verwirrt von dem Diagramm am Ende. Ich dachte, ich hätte es verstanden, bis ich dieses Bild sah.

2691voto

Brian R. Bondy Punkte 325712

Stack:

  • Im Computer-RAM gespeichert wie der Stack.
  • Variablen, die auf dem Stack erstellt werden, gehen außerhalb des Gültigkeitsbereichs und werden automatisch deallokiert.
  • Vielschneller zu allozieren im Vergleich zu Variablen auf dem Heap.
  • Implementiert mit einer tatsächlichen Stapel-Datenstruktur.
  • Speichert lokale Daten, Rücksprungadressen, wird für die Parameterübergabe verwendet.
  • Kann einen Stack-Überlauf haben, wenn zu viel des Stacks verwendet wird (meistens durch eine unendliche oder zu tiefe Rekursion, sehr große Allokationen).
  • Auf dem Stack erstellte Daten können ohne Zeiger verwendet werden.
  • Sie würden den Stack verwenden, wenn Sie genau wissen, wie viele Daten Sie vor der Kompilierungszeit zuweisen müssen und es nicht zu groß ist.
  • Hat normalerweise eine bereits vor dem Programmstart festgelegte maximale Größe.

Heap:

  • Im Computer-RAM gespeichert wie der Stack.
  • In C++ müssen Variablen auf dem Heap manuell zerstört werden und gehen niemals außerhalb des Gültigkeitsbereichs. Die Daten werden mit delete, delete[] oder free freigegeben.
  • Langsamer zu allozieren im Vergleich zu Variablen auf dem Stack.
  • Auf Abruf verwendet, um einen Block von Daten für die Verwendung durch das Programm zu allozieren.
  • Kann zu Fragmentierung führen, wenn es viele Allokationen und Deallokationen gibt.
  • In C++ oder C wird auf dem Heap erstellte Daten von Zeigern verwiesen und mit new bzw. malloc alloziert.
  • Kann Allokationsfehler haben, wenn ein zu großer Puffer angefordert wird.
  • Sie würden den Heap verwenden, wenn Sie nicht genau wissen, wie viele Daten Sie zur Laufzeit benötigen werden oder wenn Sie eine Menge Daten zuweisen müssen.
  • Verantwortlich für Speicherlecks.

Beispiel:

int foo()
{
  char *pBuffer; //<-- noch nichts alloziert (ausgenommen der Zeiger selbst, der hier auf dem Stack alloziert wird).
  bool b = true; // Auf dem Stack alloziert.
  if(b)
  {
    // Erstelle 500 Bytes auf dem Stack
    char buffer[500];

    // Erstelle 500 Bytes auf dem Heap
    pBuffer = new char[500];

   }//<-- Buffer wird hier dealloziert, pBuffer nicht
}//<--- Oops, es gibt ein Speicherleck, ich hätte delete[] pBuffer aufrufen sollen;

39 Stimmen

Der Zeiger pBuffer und der Wert von b befinden sich im Stapel und werden höchstwahrscheinlich am Eingang der Funktion zugewiesen. Je nach Compiler kann auch der Puffer am Funktionseingang zugewiesen werden.

47 Stimmen

Es herrscht oft die falsche Annahme, dass die C-Sprache, wie sie durch den C99-Sprachstandard definiert ist (verfügbar unter open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf), einen "Stack" erfordert. Tatsächlich taucht das Wort 'Stack' nicht einmal im Standard auf. Aussagen bzgl. des Stapelspeicher-Verhaltens von C sind im Allgemeinen zwar richtig, werden aber vom Standard in keiner Weise gefordert. Weitere Informationen finden Sie unter knosof.co.uk/cbook/cbook.html, insbesondere wie C auf eigenwilligen Architekturen wie den en.wikipedia.org/wiki/Burroughs_large_systems implementiert wird.

63 Stimmen

@Brian Du solltest erklären, warum buffer[] und der pBuffer-Zeiger auf dem Stapel erstellt werden und warum die Daten von pBuffer auf dem Heap erstellt sind. Ich denke, manche Leute könnten durch deine Antwort verwirrt sein, da sie vielleicht denken, dass das Programm explizit anweist, dass Speicher auf dem Stapel im Vergleich zum Heap allokiert wird, aber das ist nicht der Fall. Liegt es daran, dass Buffer ein Werttyp ist, wohingegen pBuffer ein Verweistyp ist?

1516voto

thomasrutter Punkte 109036

Der wichtigste Punkt ist, dass Heap und Stack generische Begriffe für Möglichkeiten sind, auf die Speicher zugewiesen werden kann. Sie können auf viele unterschiedliche Arten implementiert werden, und die Begriffe gelten für die grundlegenden Konzepte.

  • In einem Stapel von Elementen liegen die Elemente übereinander in der Reihenfolge, in der sie dort platziert wurden, und man kann nur das oberste entfernen (ohne das Ganze umzuwerfen).

    Stapel wie ein Stapel Papier

    Die Einfachheit eines Stacks liegt darin, dass Sie keine Tabelle mit einem Eintrag für jeden Abschnitt des zugeordneten Speichers führen müssen; die einzige Zustandsinformation, die Sie benötigen, ist ein einzelner Zeiger zum Ende des Stacks. Zum Zuweisen und Freigeben erhöhen und verringern Sie einfach diesen einzelnen Zeiger. Hinweis: Ein Stack kann manchmal so implementiert werden, dass er am oberen Ende eines Speicherbereichs beginnt und nach unten erweitert wird, anstatt nach oben zu wachsen.

  • In einem Heap gibt es keine bestimmte Reihenfolge, wie Elemente platziert werden. Sie können hineingreifen und Elemente in beliebiger Reihenfolge entfernen, da es kein klares 'oberstes' Element gibt.

    Heap wie ein Haufen Lakritzstangen

    Die Heap-Allokation erfordert die Aufrechterhaltung eines vollständigen Registers darüber, welcher Speicher zugeordnet ist und welcher nicht, sowie einige Überwachungsvorgänge zur Reduzierung von Fragmentierung, zum Auffinden zusammenhängender Speichersegmente, die groß genug sind, um die angeforderte Größe zu passen, usw. Der Speicher kann jederzeit freigegeben werden, was dann Freiraum schafft. Manchmal führt ein Speicher-Allokator Wartungsaufgaben wie das Defragmentieren des Speichers durch das Verschieben von zugeordnetem Speicher oder das Garbage-Collecting durch - das Identifizieren zur Laufzeit, wann der Speicher nicht mehr im Bereich liegt und die Freigabe davon.

Diese Bilder sollten eine ziemlich gute Arbeit dabei leisten, die beiden Möglichkeiten der Zuweisung und Freigabe von Speicher in einem Stapel und in einem Heap zu beschreiben. Lecker!

  • In welchem Maße werden sie vom Betriebssystem oder der Laufzeitumgebung der Sprache gesteuert?

    Wie erwähnt, sind Heap und Stack allgemeine Begriffe und können auf viele Arten implementiert werden. Computerprogramme haben typischerweise einen Stack namens Aufrufstack, der Informationen speichert, die für die aktuelle Funktion relevant sind, wie einen Zeiger auf die Funktion, von der aus sie aufgerufen wurde, und alle lokalen Variablen. Da Funktionen andere Funktionen aufrufen und dann zurückkehren, wächst und schrumpft der Stack, um Informationen von Funktionen weiter unten im Aufrufstapel zu halten. Ein Programm hat keine Echtzeitkontrolle darüber; dies wird durch die Programmiersprache, das Betriebssystem und sogar die Systemarchitektur bestimmt.

    Ein Heap ist ein allgemeiner Begriff für Speicher, der dynamisch und willkürlich zugeordnet wird; d. h. außerhalb der Reihenfolge. Der Speicher wird normalerweise vom Betriebssystem zugeordnet, wobei die Anwendung API-Funktionen aufruft, um diese Zuordnung durchzuführen. Die Verwaltung dynamisch zugeordneten Speichers erfordert einiges an Overhead, der normalerweise vom Laufzeitcode der verwendeten Programmiersprache oder Umgebung gehandhabt wird.

  • Was ist ihr Anwendungsbereich?

    Der Aufrufstapel ist ein so auf niedriger Ebene befindliches Konzept, dass es sich nicht auf 'Anwendungsbereich' im sinne der Programmierung bezieht. Wenn Sie einen Code disassemblieren, sehen Sie relative Zeiger-Referenzen auf Abschnitte des Stapels, aber was eine höhere Programmiersprache betrifft, legt die Sprache ihre eigenen Regeln für den Anwendungsbereich fest. Ein wichtiges Merkmal eines Stacks ist jedoch, dass nach der Rückkehr einer Funktion alles Lokale dieser Funktion sofort vom Stapel freigegeben wird. Das funktioniert so, wie man es anhand der Funktionsweise von Programmiersprachen erwarten würde. Bei einem Heap ist es ebenfalls schwer zu definieren. Der Anwendungsbereich ist das, was vom Betriebssystem offenbart wird, aber Ihre Programmiersprache fügt wahrscheinlich ihre eigenen Regeln hinzu, was ein "Anwendungsbereich" in Ihrer Anwendung ist. Die Prozessorarchitektur und das Betriebssystem verwenden virtuelle Adressierung, die der Prozessor in physische Adressen übersetzt, und es gibt Seitenfehler usw. Sie behalten im Auge, welche Seiten welchen Anwendungen gehören. Sie müssen sich jedoch normalerweise keine Gedanken darüber machen, da Sie einfach die Methode verwenden, die Ihre Programmiersprache zum Zuweisen und Freigeben von Speicher verwendet, und Fehler überprüfen (wenn das Zuweisen/Freigeben aus irgendeinem Grund fehlschlägt).

  • Was bestimmt die Größe von jedem von ihnen?

    Erneut hängt es von der Sprache, dem Compiler, dem Betriebssystem und der Architektur ab. Ein Stack wird normalerweise im Voraus zugewiesen, da er nach Definition zusammenhängender Speicher sein muss. Die Sprache, der Compiler oder das Betriebssystem bestimmen seine Größe. Sie speichern keine großen Datenblöcke auf dem Stack, sodass er groß genug ist, dass er normalerweise nie vollständig genutzt wird, außer bei unerwünschten endlosen Rekursionen (daher "Stack Overflow") oder anderen ungewöhnlichen Programmierentscheidungen.

    Ein Heap ist ein allgemeiner Begriff für alles, was dynamisch zugewiesen werden kann. Je nach Betrachtungsweise ändert sich seine Größe ständig. In modernen Prozessoren und Betriebssystemen ist die genaue Arbeitsweise sehr abstrahiert, sodass Sie sich normalerweise nicht allzu viele Gedanken darüber machen müssen, wie es tief unten funktioniert, außer dass Sie (in Sprachen, die es zulassen) keinen nicht zugewiesenen Speicher oder freigegebenen Speicher verwenden dürfen.

  • Was macht einen schneller?

    Der Stack ist schneller, weil alle freien Speicherblöcke immer zusammenhängend sind. Es muss keine Liste aller freien Speichersegmente gepflegt werden, nur ein einzelner Zeiger auf den aktuellen obersten Bereich des Stacks. Compiler speichern diesen Zeiger normalerweise in einem speziellen, schnellen Register für diesen Zweck. Darüber hinaus konzentrieren sich nachfolgende Operationen auf einem Stack normalerweise in sehr nahe beieinander liegenden Speicherbereichen, was auf einer sehr niedrigen Ebene für eine Optimierung durch die Cache-Speicher der Prozessoren vorteilhaft ist.

0 Stimmen

Falsches Bild für einen Stapel; es sollte etwas Ähnliches wie thermo-box.co.uk/images/stories/FiniW/… sein, deshalb wird es auch als 'Push-Down-Stack' bezeichnet.

27 Stimmen

David, ich stimme nicht zu, dass das ein gutes Bild ist oder dass "Push-Down-Stack" ein guter Begriff ist, um das Konzept zu veranschaulichen. Wenn Sie etwas zu einem Stapel hinzufügen, werden die anderen Inhalte des Stapels nicht nach unten gedrückt, sie bleiben dort, wo sie sind.

16 Stimmen

Diese Antwort enthält einen großen Fehler. Statische Variablen werden nicht auf dem Stapelspeicher zugewiesen. Siehe meine Antwort [link] stackoverflow.com/a/13326916/1763801 für Klarstellung. Du setzt "automatische" Variablen mit "statischen" Variablen gleich, aber sie sind überhaupt nicht dasselbe.

823voto

Martin Liversage Punkte 100306

(Ich habe diese Antwort von einer anderen Frage verschoben, die mehr oder weniger eine Kopie dieser ist.)

Die Antwort auf deine Frage ist implementierungsspezifisch und kann je nach Compiler und Prozessorarchitektur variieren. Hier ist jedoch eine vereinfachte Erklärung.

  • Sowohl der Stack als auch der Heap sind Speicherbereiche, die vom zugrunde liegenden Betriebssystem allokiert werden (oft virtueller Speicher, der bei Bedarf in physischen Speicher gemappt wird).
  • In einer Multi-Thread-Umgebung hat jeder Thread seinen eigenen vollständig unabhängigen Stack, aber sie teilen sich den Heap. Der gleichzeitige Zugriff auf den Heap muss kontrolliert werden und ist auf dem Stack nicht möglich.

Der Heap

  • Der Heap enthält eine verkettete Liste von verwendeten und freien Blöcken. Neue Allokationen im Heap (über new oder malloc) werden durch Erstellen eines geeigneten Blocks aus einem der freien Blöcke zufrieden gestellt. Dies erfordert eine Aktualisierung der Liste der Blöcke auf dem Heap. Diese Metainformationen über die Blöcke auf dem Heap werden oft auch auf dem Heap gespeichert, oft in einem kleinen Bereich direkt vor jedem Block.
  • Wenn der Heap wächst, werden neue Blöcke oft von niedrigeren Adressen zu höheren Adressen hin allokiert. Daher kann man sich den Heap als Haufen von Memoryblöcken vorstellen, der mit der Allokation von Speicher wächst. Wenn der Heap für eine Allokation zu klein ist, kann die Größe oft erhöht werden, indem mehr Speicher vom zugrunde liegenden Betriebssystem angefordert wird.
  • Das Allozieren und Deallozieren vieler kleiner Blöcke kann den Heap in einen Zustand bringen, in dem viele kleine freie Blöcke zwischen den verwendeten Blöcken liegen. Eine Anfrage zur Allokation eines großen Blocks kann fehlschlagen, weil keiner der freien Blöcke groß genug ist, um die Allokationsanfrage zu erfüllen, obwohl die kombinierte Größe der freien Blöcke groß genug sein könnte. Dies wird als Heap-Fragmentierung bezeichnet.
  • Wenn ein benutzter Block, der an einen freien Block angrenzt, deallokiert wird, kann der neue freie Block mit dem benachbarten freien Block zusammengeführt werden, um einen größeren freien Block zu erstellen, wodurch die Fragmentierung des Heaps effektiv reduziert wird.

Der Heap

Der Stack

  • Der Stack arbeitet oft eng mit einem speziellen Register auf der CPU zusammen, das als Stackpointer bezeichnet wird. Anfangs zeigt der Stackpointer auf die Spitze des Stacks (die höchste Adresse auf dem Stack).
  • Die CPU hat spezielle Anweisungen zum Pushen von Werten auf den Stack und zum Popen von Werten vom Stack. Jedes Pushen speichert den Wert an der aktuellen Position des Stackpointers und verringert den Stackpointer. Ein Pop ruft den Wert ab, auf den der Stackpointer zeigt, und erhöht dann den Stackpointer (lass dich nicht davon verwirren, dass das Hinzufügen eines Werts auf den Stack den Stackpointer verringert und das Entfernen eines Werts ihn erhöht. Denke daran, dass der Stack nach unten wächst). Die gespeicherten und abgerufenen Werte sind die Werte der CPU-Register.
  • Wenn eine Funktion Parameter hat, werden diese vor dem Funktionsaufruf auf den Stack geschoben. Der Code in der Funktion kann dann derzeit vom Stackpointer aus durch den Stack navigieren, um diese Werte zu finden.
  • Wenn eine Funktion aufgerufen wird, verwendet die CPU spezielle Anweisungen, die den aktuellen Instruction Pointer auf den Stack schieben, d.h. die Adresse des auf dem Stack ausgeführten Codes. Die CPU springt dann zur Funktion, indem der Instruction Pointer auf die Adresse der aufgerufenen Funktion gesetzt wird. Später, wenn die Funktion zurückkehrt, wird der alte Instruction Pointer vom Stack genommen und die Ausführung wird an dem Code fortgesetzt, der direkt nach dem Funktionsaufruf liegt.
  • Wenn eine Funktion betreten wird, wird der Stackpointer verringert, um mehr Speicher auf dem Stack für lokale (automatische) Variablen zuzuweisen. Wenn die Funktion eine lokale 32-Bit-Variable hat, werden vier Bytes auf dem Stack reserviert. Wenn die Funktion zurückkehrt, wird der Stackpointer zurückgeführt, um den allokierten Bereich freizugeben.
  • Verschachtelte Funktionsaufrufe funktionieren einwandfrei. Jeder neue Aufruf allokiert Funktionsparameter, die Rückadresse und Platz für lokale Variablen, und diese Aktivierungseinträge können für verschachtelte Aufrufe gestapelt werden und werden auf korrekte Weise aufgelöst, wenn die Funktionen zurückkehren.
  • Da der Stack ein begrenzter Speicherbereich ist, kann ein Stacküberlauf durch zu viele verschachtelte Funktionen und/oder zu viel allokiertem Speicher für lokale Variablen verursacht werden. Oft wird der Speicherbereich, der für den Stack verwendet wird, so eingerichtet, dass das Schreiben unterhalb des Bodens (der niedrigsten Adresse) des Stacks einen Trap oder eine Ausnahme in der CPU auslöst. Dieser Ausnahmefall kann dann vom Laufzeitsystem erfasst und in eine Art von Stacküberlaufausnahme umgewandelt werden.

Der Stack

Kann eine Funktion auf dem Heap anstelle eines Stacks allokiert werden?

Nein, Aktivierungseinträge für Funktionen (d.h. lokale oder automatische Variablen) werden auf dem Stack allokiert, der nicht nur zur Speicherung dieser Variablen verwendet wird, sondern auch dazu dient, verschachtelte Funktionsaufrufe zu verfolgen.

Wie der Heap verwaltet wird, obliegt wirklich der Laufzeitumgebung. C verwendet malloc und C++ verwendet new, aber viele andere Sprachen haben Garbage Collection.

Der Stack ist jedoch ein mehr auf Prozessorarchitektur bezogenes Low-Level-Feature. Das Wachsen des Heaps, wenn nicht genügend Platz vorhanden ist, ist nicht allzu schwierig, da dies in der Bibliotheksfunktion implementiert werden kann, die den Heap verwaltet. Das Wachsen des Stacks ist jedoch oft unmöglich, da ein Stacküberlauf erst entdeckt wird, wenn es zu spät ist; und das Abschalten des Ausführungsthreads ist die einzige praktikable Option.

42 Stimmen

@Martin - Eine wirklich gute Antwort/Erklärung als die abstraktere akzeptierte Antwort. Ein Beispiel-Assemblierungsprogramm, das die Verwendung von Stackpointern/Registern in Bezug auf Funktionsaufrufe zeigt, wäre anschaulicher.

5 Stimmen

Jeder Referenztyp ist eine Zusammensetzung von Werttypen (int, string usw.). Wie bereits erwähnt, werden Werttypen im Stack gespeichert. Wie funktioniert das, wenn sie Teil eines Referenztyps sind?

23 Stimmen

Diese Antwort war meiner Meinung nach die beste, weil sie mir geholfen hat zu verstehen, was eine Rückgabeanweisung wirklich ist und wie sie mit dieser "Rückgabeadresse" zusammenhängt, auf die ich hin und wieder stoße, was es bedeutet, eine Funktion auf den Stapel zu legen, und warum Funktionen auf Stapeln geschoben werden. Tolle Antwort!

448voto

Snowcrash Punkte 73122

In dem folgenden C# Code

public void Method1()
{
    int i = 4;
    int y = 2;
    class1 cls1 = new class1();
}

So wird der Speicher verwaltet

Bild von Variablen auf dem Stack

Lokale Variablen, die nur während des Funktionsaufrufs benötigt werden, werden auf dem Stack abgelegt. Der Heap wird für Variablen verwendet, deren Lebensdauer wir nicht im Voraus kennen, aber von denen wir erwarten, dass sie eine Weile dauern. In den meisten Sprachen ist es entscheidend zu wissen, wie groß eine Variable zur Kompilierzeit ist, wenn wir sie auf dem Stack speichern wollen.

Objekte (deren Größe sich ändert, wenn wir sie aktualisieren) werden auf dem Heap abgelegt, da wir zum Zeitpunkt der Erstellung nicht wissen, wie lange sie dauern werden. In vielen Sprachen wird der Heap durch Garbage Collection aufgeräumt, um Objekte (wie das cls1-Objekt) zu finden, auf die nicht mehr verwiesen wird.

In Java werden die meisten Objekte direkt in den Heap gelegt. In Sprachen wie C / C++ können structs und Klassen oft auf dem Stack bleiben, wenn man es nicht mit Pointern zu tun hat.

Mehr Informationen finden Sie hier:

Der Unterschied zwischen Stack- und Heap-Speicherzuweisung « timmurphy.org

und hier:

Objekte auf dem Stack und auf dem Heap erstellen

Dieser Artikel ist die Quelle des obigen Bildes: Sechs wichtige .NET-Konzepte: Stack, Heap, Werttypen, Referenztypen, Boxing und Unboxing - CodeProject

aber bitte beachten Sie, dass er möglicherweise einige Ungenauigkeiten enthält.

1 Stimmen

Wenn Sie meinen Ruf überprüfen, können Sie sehen, dass ich noch nicht abstimmen kann. Also bin nicht einmal ich derjenige, der abstimmt.

17 Stimmen

Das ist falsch. i und cls sind keine "statischen" Variablen. Sie werden als "lokale" oder "automatische" Variablen bezeichnet. Dies ist eine sehr wichtige Unterscheidung. Siehe [link] stackoverflow.com/a/13326916/1763801 zur Klärung

10 Stimmen

Ich habe nicht gesagt, dass sie statische Variablen sind. Ich habe gesagt, dass int und cls1 statische Elemente sind. Ihr Speicher wird statisch zugeordnet und daher werden sie auf dem Stapel abgelegt. Dies steht im Gegensatz zu einem Objekt, das eine dynamische Speicherzuordnung erfordert und daher auf dem Heap abgelegt wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X