Frage

In Büchern über Programmiersprachen wird erklärt, dass Werttypen auf dem erstellt werden Stapel, und Referenztypen werden auf der erstellt Haufen, ohne zu erklären, was diese beiden Dinge sind.Ich habe keine klare Erklärung dazu gelesen.Ich verstehe was ein Stapel Ist.Aber,

  • Wo und was sind sie (physisch im Speicher eines echten Computers)?
  • Inwieweit werden sie vom Betriebssystem oder der Sprachlaufzeit gesteuert?
  • Welchen Umfang haben sie?
  • Was bestimmt die Größe jedes einzelnen von ihnen?
  • Was macht einen schneller?
War es hilfreich?

Lösung

Der Stapel ist der Speicher zur Seite, als Scratch-Bereich für einen Ausführungs-Thread gesetzt. Wenn eine Funktion aufgerufen wird, wird ein Block auf der Oberseite des Stapels für lokale Variablen und einige Buchhaltungsdaten vorbehalten. Wenn diese Funktion zurückgibt, wird der Block nicht verwendet und kann das nächste Mal verwendet wird, wird eine Funktion aufgerufen. Der Stapel wird stets in einem LIFO reserviert (last in first out) Reihenfolge; der zuletzt reservierte Block ist immer der nächste Block befreit werden. Dies macht es wirklich einfach den Überblick über den Stapel zu halten; einen Block vom Stapel zu befreien ist nichts anderes als einen Zeiger eingestellt wird.

Der Haufen ist Speicher die für eine dynamische Zuordnung. Im Gegensatz zu dem Stapel, gibt es keine erzwungene Muster auf die Zuweisung und Freigabe von Blöcken aus dem Haufen; Sie können einen Block jederzeit zuweisen und es jederzeit frei. Dies macht es sehr viel komplexer, um zu verfolgen, welche Teile des Heap zugewiesen werden oder frei zu einem bestimmten Zeitpunkt; es gibt viele individuelle Haufen Verteilern für verschiedene Nutzungsmuster abzustimmen Heap Leistung zur Verfügung.

Jeder Thread bekommt einen Stapel, während es nur ein Haufen für die Anwendung in der Regel ist (obwohl es nicht ungewöhnlich, dass mehrere Haufen für verschiedene Arten von Zuordnung haben).

Um Ihre Fragen direkt zu beantworten:

  

Inwieweit werden sie von den OS oder Language Runtime gesteuert?

Das O ordnet den Stapel für jeden Systemebene-Thread, wenn der Thread erstellt wird. Typischerweise ist das O von der Sprache Laufzeit aufgerufen wird, um den Heap für die Anwendung zuzuordnen.

  

Was ist ihr Anwendungsbereich?

Der Stapel ist mit einem Gewinde angebracht ist, so dass, wenn der Thread beendet wird der Stapel zurückgewonnen. Der Haufen wird in der Regel beim Start der Anwendung durch die Laufzeit zugewiesen und freigegeben wird, wenn die Anwendung (technisch-Prozess) beendet wird.

  

Was die Größe eines jeden von ihnen bestimmt?

Die Größe des Stapels gesetzt wird, wenn ein Thread erstellt wird. Die Größe des Haufens auf Start der Anwendung eingestellt ist, kann aber wachsen als Speicherplatz benötigt wird (die Zuordner mehr Speicher vom Betriebssystem anfordert).

  

Was macht man schneller?

Der Stapel ist schneller, weil die Zugriffsmuster von ihm zu vergeben und ausplanen Speichern es trivial machen (ein Zeiger / integer wird einfach erhöht oder erniedrigt), während der Haufen in einer Zuordnung oder Aufhebung der Zuordnung beteiligte viele komplexe Buchhaltung hat. Auch neigt jedes Byte in dem Stapel werden sehr häufig wiederverwendet, was bedeutet, es neigt dazu, den Cache des Prozessors zugeordnet werden, so dass es sehr schnell. Eine weitere Performance-Einbußen für den Heap sind, dass der Haufen, wobei meist eine globale Ressource, in der Regel seinen Multi-Threading sicher hat, dh jede Zuordnung und Aufhebung der Zuordnung muss sein - in der Regel - synchronisiert mit „alle“ anderen Haufen greifen in dem Programm <. / p>

Eine klare Demonstration:
Bildquelle: vikashazrati .wordpress.com

Andere Tipps

Stack:

  • Gespeicherte in Computer RAM wie der Heap.
  • Variablen auf dem Stapel erstellt werden außerhalb des Gültigkeitsbereichs gehen und werden automatisch freigegeben.
  • Viele schneller im Vergleich zu Variablen auf dem Heap zugewiesen werden.
  • Umgesetzt mit einer aktuellen Stack-Datenstruktur.
  • Speichert lokale Daten, Adressen zurückgeben, für die Parameterübergabe verwendet.
  • Kann einen Stapelüberlauf hat, wenn zu viel des Stapels verwendet wird (vor allem aus unendlich oder zu tief Rekursion, sehr großen Zuordnungen).
  • Daten auf dem Stapel erstellt wurden, können ohne Zeiger verwendet werden.
  • Sie würden die Stapel verwenden, wenn Sie genau wissen, wie viele Daten Sie zuweisen müssen, bevor die Zeit kompilieren, und es ist nicht zu groß.
  • hat in der Regel eine maximale Größe bereits festgelegt, wenn das Programm gestartet wird.

Heap:

  • Gespeicherte in Computer RAM wie der Stapel.
  • In C ++ Variablen auf dem Heap muss manuell zerstört werden und fallen nie aus der Anwendungsbereich. Die Daten werden befreit mit delete, delete[] oder free.
  • Langsamer im Vergleich zu Variablen auf dem Stack zugeordnet werden.
  • bei Bedarf verwendet, um einen Block von Daten für die Verwendung durch das Programm zuzuweisen.
  • Kann Fragmentierung haben, wenn es eine Menge von Zuweisungen und Freigaben ist.
  • In C ++ oder C, auf dem Heap erstellt Daten werden durch Zeiger und jeweils mit new oder malloc zugeordnet hingewiesen werden.
  • Kann Zuordnungsfehler, wenn zu groß eines Puffers angefordert wird zugeteilt werden.
  • Sie würden den Heap verwenden, wenn Sie nicht genau wissen, wie viele Daten Sie zur Laufzeit benötigt, oder wenn Sie eine Menge Daten zuweisen müssen.
  • Verantwortlich für Speicherlecks.

Beispiel:

int foo()
{
  char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack).
  bool b = true; // Allocated on the stack.
  if(b)
  {
    //Create 500 bytes on the stack
    char buffer[500];

    //Create 500 bytes on the heap
    pBuffer = new char[500];

   }//<-- buffer is deallocated here, pBuffer is not
}//<--- oops there's a memory leak, I should have called delete[] pBuffer;

Der wichtigste Punkt ist, dass Heap und Stack allgemeine Begriffe für die Art und Weise sind, wie Speicher zugewiesen werden kann.Sie können auf viele verschiedene Arten umgesetzt werden und die Begriffe gelten für die Grundkonzepte.

  • In einem Stapel von Gegenständen liegen die Gegenstände in der Reihenfolge übereinander, in der sie dort platziert wurden, und Sie können nur den obersten Gegenstand entfernen (ohne dass der ganze Gegenstand umkippt).

    Stack like a stack of papers

    Die Einfachheit eines Stapels besteht darin, dass Sie keine Tabelle verwalten müssen, die einen Datensatz für jeden Abschnitt des zugewiesenen Speichers enthält.Die einzige Statusinformation, die Sie benötigen, ist ein einzelner Zeiger auf das Ende des Stapels.Zum Zuweisen und Aufheben der Zuweisung erhöhen und dekrementieren Sie einfach diesen einzelnen Zeiger.Notiz:Manchmal kann ein Stapel so implementiert werden, dass er oben in einem Speicherabschnitt beginnt und sich nach unten erstreckt, anstatt nach oben zu wachsen.

  • In einem Heap gibt es keine bestimmte Reihenfolge für die Platzierung der Elemente.Sie können in beliebiger Reihenfolge hineingreifen und Elemente entfernen, da es kein klares „Top“-Element gibt.

    Heap like a heap of licorice allsorts

    Für die Heap-Zuweisung ist es erforderlich, eine vollständige Aufzeichnung darüber zu führen, welcher Speicher zugewiesen ist und welcher nicht. Außerdem ist ein gewisser Verwaltungsaufwand erforderlich, um die Fragmentierung zu reduzieren, zusammenhängende Speichersegmente zu finden, die groß genug sind, um der angeforderten Größe zu entsprechen, und so weiter.Die Speicherzuweisung kann jederzeit aufgehoben werden, sodass freier Speicherplatz verbleibt.Manchmal führt ein Speicherzuweiser Wartungsaufgaben durch, z. B. die Defragmentierung des Speichers durch Verschieben des zugewiesenen Speichers oder die Müllsammlung, bei der zur Laufzeit festgestellt wird, wann sich der Speicher nicht mehr im Gültigkeitsbereich befindet, und die Zuordnung aufgehoben wird.

Diese Bilder sollten die beiden Möglichkeiten zum Zuweisen und Freigeben von Speicher in einem Stapel und einem Heap recht gut beschreiben.Lecker!

  • Inwieweit werden sie vom Betriebssystem oder der Sprachlaufzeit gesteuert?

    Wie bereits erwähnt, sind Heap und Stack allgemeine Begriffe und können auf viele Arten implementiert werden.Computerprogramme verfügen normalerweise über einen Stapel namens a Aufrufstapel Hier werden für die aktuelle Funktion relevante Informationen gespeichert, beispielsweise ein Zeiger auf die Funktion, von der aus sie aufgerufen wurde, sowie alle lokalen Variablen.Da Funktionen andere Funktionen aufrufen und dann zurückkehren, wächst und schrumpft der Stapel, um Informationen von den Funktionen weiter unten im Aufrufstapel aufzunehmen.Ein Programm hat keine wirkliche Laufzeitkontrolle darüber;es wird durch die Programmiersprache, das Betriebssystem und sogar die Systemarchitektur bestimmt.

    Ein Heap ist ein allgemeiner Begriff für jeden Speicher, der dynamisch und zufällig zugewiesen wird.d.h.außer Betrieb.Der Speicher wird normalerweise vom Betriebssystem zugewiesen, wobei die Anwendung API-Funktionen aufruft, um diese Zuweisung vorzunehmen.Die Verwaltung des dynamisch zugewiesenen Speichers erfordert einen erheblichen Mehraufwand, der normalerweise vom Betriebssystem übernommen wird.

  • Welchen Umfang haben sie?

    Der Aufrufstapel ist ein so untergeordnetes Konzept, dass er keinen Bezug zum „Bereich“ im Sinne der Programmierung hat.Wenn Sie Code zerlegen, werden Sie relative Verweise im Zeigerstil auf Teile des Stapels sehen, aber was eine Sprache höherer Ebene betrifft, legt die Sprache ihre eigenen Gültigkeitsregeln fest.Ein wichtiger Aspekt eines Stapels besteht jedoch darin, dass nach der Rückkehr einer Funktion alles, was lokal zu dieser Funktion gehört, sofort vom Stapel freigegeben wird.Das funktioniert so, wie Sie es angesichts der Funktionsweise Ihrer Programmiersprachen erwarten würden.In einem Heap ist es auch schwer zu definieren.Der Bereich ist das, was das Betriebssystem bereitstellt, aber Ihre Programmiersprache fügt wahrscheinlich ihre Regeln darüber hinzu, was ein „Bereich“ in Ihrer Anwendung ist.Die Prozessorarchitektur und das Betriebssystem verwenden virtuelle Adressierung, die der Prozessor in physische Adressen übersetzt und es kommt zu Seitenfehlern usw.Sie verfolgen, welche Seiten zu welchen Anwendungen gehören.Sie müssen sich darüber jedoch nie wirklich Sorgen machen, da Sie einfach die Methode verwenden, die Ihre Programmiersprache zum Zuweisen und Freigeben von Speicher verwendet, und auf Fehler prüfen (falls die Zuweisung/Freigabe aus irgendeinem Grund fehlschlägt).

  • Was bestimmt die Größe jedes einzelnen von ihnen?

    Auch hier kommt es auf die Sprache, den Compiler, das Betriebssystem und die Architektur an.Ein Stapel wird normalerweise vorab zugewiesen, da es sich per Definition um zusammenhängenden Speicher handeln muss (mehr dazu im letzten Absatz).Der Sprachcompiler oder das Betriebssystem bestimmen seine Größe.Sie speichern keine großen Datenmengen auf dem Stapel, daher ist er groß genug, dass er nie vollständig genutzt werden sollte, außer in Fällen unerwünschter endloser Rekursion (daher „Stapelüberlauf“) oder anderer ungewöhnlicher Programmierentscheidungen.

    Ein Heap ist ein allgemeiner Begriff für alles, was dynamisch zugewiesen werden kann.Je nachdem, von welcher Seite man es betrachtet, verändert es ständig seine Größe.In modernen Prozessoren und Betriebssystemen ist die genaue Funktionsweise ohnehin sehr abstrahiert, sodass Sie sich normalerweise keine großen Gedanken darüber machen müssen, wie es im Grunde funktioniert, außer dass Sie (in Sprachen, in denen dies möglich ist) den Speicher nicht so stark beanspruchen dürfen Sie haben noch keinen Speicher zugewiesen oder Speicher, den Sie freigegeben haben.

  • Was macht einen schneller?

    Der Stapel ist schneller, da der gesamte freie Speicher immer zusammenhängend ist.Es muss keine Liste aller Segmente des freien Speichers geführt werden, sondern lediglich ein einzelner Zeiger auf die aktuelle Spitze des Stapels.Compiler speichern diesen Zeiger normalerweise in einer speziellen, schnellen registrieren für diesen Zweck.Darüber hinaus konzentrieren sich nachfolgende Vorgänge auf einem Stapel normalerweise auf sehr nahegelegene Speicherbereiche, was auf einer sehr niedrigen Ebene gut für die Optimierung durch die On-Die-Caches des Prozessors ist.

(ich diese Antwort von einer anderen Frage bewegt habe, die mehr oder weniger eine Betrogene dies war.)

Die Antwort auf Ihre Frage ist Implementierung spezifischer und über Compiler und Prozessor-Architekturen variieren. Doch hier ist eine vereinfachte Erklärung.

  • Sowohl der Stack und der Heap sind Speicherbereiche aus dem zugrunde liegenden Betriebssystem zugeordnet (oft virtuellen Speicher, die physischen Speicher auf Anforderung abgebildet wird).
  • In einer Multithread-Umgebung jeder Thread seine eigenen völlig unabhängig Stapel hat, aber sie werden die Haufen teilen. Gleichzeitiger Zugriff hat auf dem Heap zu steuern und ist nicht möglich, auf dem Stapel.

Der Haufen

  • Der Haufen enthält eine verknüpfte Liste der aktuell verfügbaren und freien Blöcke. Neue Zuteilungen auf dem Heap (durch new oder malloc) erfüllt werden, indem einen geeigneten Block von einem der freien Blöcke zu schaffen. Dies erfordert die Aktualisierung Liste der Blöcke auf dem Heap. Diese Meta-Informationen über die Blöcke auf dem Heap auch auf dem Heap oft in einem kleinen Bereich direkt vor jedem Block gespeichert sind.
  • Wie die Heap neue Blöcke wächst oft von unteren Adressen zu höheren Adressen zugeordnet sind. So können Sie von der Halde denken als heap von Speicherblöcken, die in der Größe wächst als Speicher zugeordnet ist. Wenn der Heap für eine Zuteilung zu klein ist, kann die Größe oft durch den Erwerb von mehr Speichern aus dem zugrunde liegenden Betriebssystem erhöht werden.
  • Die Zuweisung und das Aufheben von Zuweisungen viele kleine Blöcke können den Heap in einem Zustand verlassen, in dem viele kleine freie Blöcke gibt es zwischen den verwendeten Blöcken durchsetzt. Eine Anforderung einen großen Block zuweisen kann fehlschlagen, weil keine der freien Blöcke sind groß genug, um die Zuweisungsanforderung selbst zu befriedigen, obwohl die Gesamtgröße der freien Blöcke groß genug sein kann. Dies nennt man Heapfragmentierung .
  • Wenn ein verwendeter Block, der an einen freien Block angrenzt, um den neuen freien Block freigegeben mit dem benachbarten freien Block zusammengefügt werden, um einen größeren freien Block effektiv die Fragmentierung der Heap-Reduzierung zu schaffen.

Der Haufen

Der Stapel

  • Der Stapel arbeitet oft in engem Tandem mit einem speziellen Register auf der CPU des Stapelzeiger genannt. Zunächst werden die Stapelzeiger zeigt auf die Oberseite des Stapels (die höchste Adresse auf dem Stapel).
  • Die CPU verfügt über spezielle Anweisungen für drücken Werte auf den Stapel und popping sie aus dem Stapel zurück. Jeder Push speichert den Wert an der aktuellen Position des Stapelzeigers und verringert den Stapelzeiger. A Pop ruft der Wert durch den Stapelzeiger gezeigt und erhöht dann den Stapelzeiger (nicht durch die Tatsache verwechselt werden, dass Hinzufügen ein Wert auf den Stapel verringert der Stapelzeiger und Entfernen ein Wert erhöht es. Denken sie daran, dass der Stapel auf dem Boden wächst). Die Werte gespeichert und abgerufen sind die Werte der CPU-Register.
  • Wenn eine Funktion verwendet die CPU spezielle Anweisungen aufgerufen wird, die die aktuelle Befehlszeiger , das heißt die Adresse des Codes der Ausführung auf dem Stapel schieben. Die CPU springt dann auf die Funktion, die durch die Einstellung Befehlszeiger auf die Adresse der Funktion genannt. Später, wenn die Funktion zurück, der alte Befehlszeiger wird aus dem Stapel genommen und Ausführung wieder auf dem Code unmittelbar nach dem Aufruf der Funktion.
  • Wenn eine Funktion eingegeben wird, wird der Stapelzeiger verringert mehr Platz auf dem Stapel für die lokale (automatische) Variablen zuzuordnen. Wenn die Funktion ein lokales 32-Bit-Variable vier Bytes hat, wird beiseite gesetzt auf dem Stapel. Wenn die Funktion zurückkehrt, wird der Stapelzeiger bewegt zurück, um den zugewiesenen Bereich zu befreien.
  • Wenn eine Funktion Parameter hat, werden diese auf den Stapel vor dem Aufruf der Funktion gedrückt. Der Code in der Funktion ist dann in der Lageden Stapel aus dem aktuellen Stapelzeiger zu navigieren, diese Werte zu suchen.
  • Nesting-Funktion Anrufe funktionieren wie ein Zauber. Jeder neue Anruf-Funktion Parameter zuweisen wird, die Absenderadresse und Raum für lokale Variablen und diese Aktivierung Aufzeichnungen für verschachtelte Aufrufe gestapelt werden und in der richtigen Art und Weise entspannen, wenn die Funktionen zurück.
  • Da der Stapel eine begrenzte Speicherblock ist, können Sie ein Stack-Überlauf verursachen, indem sie zu viele verschachtelte Funktionen aufrufen und / oder für lokale Variablen zu viel Platz zuweist. Oft ist der Speicherbereich für den Stapel verwendet wird, in einer solchen Art und Weise eingerichtet, die unterhalb des unteren Schreiben (die niedrigste Adresse) des Stapels wird eine Trap oder Ausnahme in der CPU auslösen. Diese außergewöhnliche Bedingung kann dann von der Laufzeit und umgewandelt in eine Art Stack-Überlauf Ausnahme abgefangen werden.

Der Stapel

  

Kann eine Funktion auf dem Heap statt einem Stapel zugeordnet werden?

Nein, Aktivierung Datensätze für Funktionen (das heißt lokale oder automatische Variablen) auf dem Stapel reserviert, der verwendet wird, nicht nur diese Variablen zu speichern, sondern auch den Überblick über verschachtelte Funktionsaufrufe zu halten.

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

Allerdings ist der Stapel eine Low-Level-Funktion eng mit der Prozessorarchitektur gebunden. Wachsende den Haufen, wenn es nicht genug Platz ist nicht allzu schwer, da sie in der Bibliothek Aufruf implementiert werden kann, der den Heap behandelt. Allerdings ist der Stapel wächst oft unmöglich, da der Stack-Überlauf erst entdeckt wird, wenn es zu spät ist; und Abschalten des Thread der Ausführung ist die einzig gangbare Option.

Im folgenden C # -Code

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

Hier ist, wie der Speicher verwaltet wird,

Bild von Variablen auf dem Stapel

Local Variables, die nur noch so lange dauern wie der Funktionsaufruf in dem Stapel. Der Haufen wird für Variablen verwendet, deren Lebensdauer wir nicht wirklich vorne weiß, aber wir erwarten, dass sie eine Weile dauern. In den meisten Sprachen ist es wichtig, dass wir bei der Kompilierung wissen, wie groß eine Variable ist, wenn wir es auf dem Stapel gespeichert werden sollen.

Objekte (die in der Größe variieren, wie wir sie aktualisieren) gehen auf dem Heap, weil wir zum Zeitpunkt der Erstellung nicht wissen, wie lange sie dauern werden. In vielen Sprachen ist der Haufen Müll gesammelt Objekte (wie das CLS1 Objekt) zu finden, die nicht mehr alle Verweise hat.

In Java, gehen die meisten Objekte direkt in den Haufen. In Sprachen wie C / C ++, structs und Klassen können bleiben oft auf dem Stapel, wenn Sie nicht mit Zeigern zu tun.

Weitere Informationen finden Sie hier:

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

und hier:

Sechs wichtige .NET-Konzepte: Stapel, Haufen, Werttypen, Referenztypen, Boxen und Unboxing - Codeproject

aber bewusst sein, es einige Ungenauigkeiten enthalten.

Der Stapel Wenn Sie eine Funktion, die Argumente aufrufen, um diese Funktion sowie einige andere Overhead auf den Stapel gelegt. Einige Informationen (wie zum Beispiel, wo bei der Rückkehr gehen) werden auch dort gespeichert. Wenn Sie eine Variable in Ihrer Funktion deklarieren, wird diese Variable auch auf dem Stack zugeordnet.

den Stapel freigibt, ist ziemlich einfach, weil Sie immer in der umgekehrten Reihenfolge freigeben, in dem Sie zuordnen. Stapel Material hinzugefügt wird, wie Sie Funktionen eingeben, werden die entsprechenden Daten entfernt, wie Sie sie verlassen. Dies bedeutet, dass Sie neigen dazu, in einem kleinen Bereich des Stapels zu bleiben, wenn Sie viele Funktionen aufrufen, die viele andere Funktionen aufrufen (oder eine rekursive Lösung erstellen).

Die Heap Der Haufen ist ein allgemeiner Name für, wo Sie die Daten setzen, die Sie im laufenden Betrieb erstellen. Wenn Sie nicht wissen, wie viele Raumschiffe Ihres Programm erstellen wird, werden Sie wahrscheinlich den neuen (oder malloc oder gleichwertig) Operator verwenden, um jedes Raumschiff zu erstellen. Diese Zuordnung wird für eine Weile bleiben, um, so ist es wahrscheinlich, wir die Dinge in einer anderen Reihenfolge befreien, als wir sie geschaffen hat.

Damit ist der Haufen weitaus komplexer ist, denn es gibt Bereiche des Speichers am Ende werden, die mit Stücken ungenutzt verschachtelt sind, die - Speicher wird fragmentiert. freien Speicher der Größe zu finden, was Sie brauchen ist ein schwieriges Problem. Aus diesem Grunde sollte der Haufen vermieden werden (obwohl es immer noch verwendet wird, oft).

Die Umsetzung Die Umsetzung sowohl den Stack und Heap ist in der Regel bis auf die Laufzeit / O. Oft Spiele und andere Anwendungen, die Leistung sind entscheidend, ihre eigenen Speicherlösungen schaffen, die einen großen Teil des Speichers aus dem Haufen packen und sie dann intern auszuteilen zu vermeiden, auf dem O für das Gedächtnis verlassen.

Dies ist nur sinnvoll, wenn die Speicherauslastung von der Norm ganz anders ist - d. H für Spiele, bei denen Sie eine Ebene in einem großen Betrieb geladen wird und können die ganze Menge weg in einem anderen großen Betrieb Futter

Stelle im Speicher Dies ist weniger relevant, als Sie wegen einer Technologie namens Virtual Memory denken, die Ihr Programm macht denken, dass Sie haben Zugriff auf eine bestimmte Adresse, wo die physikalischen Daten irgendwo anders ist (auch auf der Festplatte!). Die Adressen, die Sie für den Stapel zu bekommen sind in aufsteigender Reihenfolge als Ihr Anruf Baum tiefer wird. Die Adressen für den Heap sind un-vorhersehbare (d implimentation spezifisch) und ehrlich gesagt nicht so wichtig.

Um zu klären, diese Antwort falsche Informationen hat ( thomas richtete seine Antwort nach Kommentaren, cool :)). Andere Antworten nur vermeiden, zu erklären, was statische Zuordnung bedeutet. So werde ich erklären, die drei wichtigsten Formen der Zuteilung und wie sie in der Regel auf dem Heap, Stack beziehen und Datensegment unten. Ich werde auch einige Beispiele sowohl in C / C ++ zeigen und Python zu helfen, Menschen zu verstehen.

"Static" (AKA statisch zugewiesen) Variablen nicht auf dem Stack zugeordnet. Gehen Sie nicht davon so - viele Menschen tun, nur weil „statisch“ viel wie „Stack“ klingt. Sie existieren tatsächlich weder in dem Stapel noch den Haufen. Das sind Teil dessen, was die Datensegment genannt wird.

Es ist jedoch im Allgemeinen besser zu berücksichtigen " Anwendungsbereich " und " Lebensdauer " und nicht als "Stack" und "Halde".

Anwendungsbereich bezieht sich auf welche Teile des Codes eine Variable zugreifen können. Im Allgemeinen denken wir an lokaler Bereich (kann nur durch die aktuelle Funktion aufgerufen werden) im Vergleich zu globale Reichweite (kann überall zugegriffen werden), obwohl Umfang wesentlich komplexer erhalten.

Lebensdauer bezieht sich auf, wenn eine Variable zugeordnet ist und während der Programmausführung freigegeben. Normalerweise denken wir von statischer Zuordnung (Variable wird bestehen bleiben über die gesamte Laufzeit des Programms, so dass es nützlich für die Speicherung der gleichen Informationen über mehrere Funktionsaufrufe) im Vergleich zu automatische Zuordnung (variable nur bleibt während eines einzigen Aufruf einer Funktion, ist es nützlich zum Speichern von Informationen zu machen, die nur während Ihrer Funktion verwendet wird und entsorgt werden können, sobald Sie fertig sind) im Vergleich zu dynamische Zuordnung (Variablen, deren Dauer zur Laufzeit definiert ist statt der Kompilierung wie statische oder automatisch).

Obwohl die meisten Compiler und Interpreter dieses Verhalten implementieren ähnlich in Bezug auf die Verwendung Stapel, Haufen, etc, ein Compiler manchmal diese Konventionen brechen, wenn es so lange will als Verhalten korrekt ist. Zum Beispiel durch eine lokale Variable Optimierung kann nur in einem Register existieren oder ganz entfernt werden, obwohl die meisten lokalen Variablen in dem Stapel vorhanden sind. Wie in einigen Kommentaren darauf hingewiesen worden ist, können Sie einen Compiler implementieren, die nicht einmal einen Stapel verwendet oder einen Haufen, sondern einige andere Speichermechanismen (selten getan, da Stapel und Haufen für diese groß sind).

Ich werde einige einfache kommentierten C-Code zur Verfügung stellen, um all dies veranschaulichen. Der beste Weg zu lernen, ist ein Programm unter einem Debugger laufen und das Verhalten zu beobachten. Wenn Sie es vorziehen, Python zu lesen, bis zum Ende der Antwort überspringen:)

// Statically allocated in the data segment when the program/DLL is first loaded
// Deallocated when the program/DLL exits
// scope - can be accessed from anywhere in the code
int someGlobalVariable;

// Statically allocated in the data segment when the program is first loaded
// Deallocated when the program/DLL exits
// scope - can be accessed from anywhere in this particular code file
static int someStaticVariable;

// "someArgument" is allocated on the stack each time MyFunction is called
// "someArgument" is deallocated when MyFunction returns
// scope - can be accessed only within MyFunction()
void MyFunction(int someArgument) {

    // Statically allocated in the data segment when the program is first loaded
    // Deallocated when the program/DLL exits
    // scope - can be accessed only within MyFunction()
    static int someLocalStaticVariable;

    // Allocated on the stack each time MyFunction is called
    // Deallocated when MyFunction returns
    // scope - can be accessed only within MyFunction()
    int someLocalVariable;

    // A *pointer* is allocated on the stack each time MyFunction is called
    // This pointer is deallocated when MyFunction returns
    // scope - the pointer can be accessed only within MyFunction()
    int* someDynamicVariable;

    // This line causes space for an integer to be allocated in the heap
    // when this line is executed. Note this is not at the beginning of
    // the call to MyFunction(), like the automatic variables
    // scope - only code within MyFunction() can access this space
    // *through this particular variable*.
    // However, if you pass the address somewhere else, that code
    // can access it too
    someDynamicVariable = new int;


    // This line deallocates the space for the integer in the heap.
    // If we did not write it, the memory would be "leaked".
    // Note a fundamental difference between the stack and heap
    // the heap must be managed. The stack is managed for us.
    delete someDynamicVariable;

    // In other cases, instead of deallocating this heap space you
    // might store the address somewhere more permanent to use later.
    // Some languages even take care of deallocation for you... but
    // always it needs to be taken care of at runtime by some mechanism.

    // When the function returns, someArgument, someLocalVariable
    // and the pointer someDynamicVariable are deallocated.
    // The space pointed to by someDynamicVariable was already
    // deallocated prior to returning.
    return;
}

// Note that someGlobalVariable, someStaticVariable and
// someLocalStaticVariable continue to exist, and are not
// deallocated until the program exits.

Eine besonders ergreifende Beispiel dafür, warum es wichtig ist zwischen Lebenszeit und Umfang zu unterscheiden ist, dass eine Variable lokalen Bereich, aber statische Lebensdauer haben kann - zum Beispiel „someLocalStaticVariable“ in dem Codebeispiel oben. Solche Variablen können unsere gemeinsame, aber informelle Namensgebung Gewohnheiten sehr verwirrend. Zum Beispiel, wenn wir sagen " local " wir in der Regel bedeuten " scoped lokal automatisch zugewiesene Variable ", und wenn wir global sagen, dass wir in der Regel bedeuten „ global statisch zugewiesene Variable scoped “. Leider, wenn es um Dinge wie kommt " scoped Datei statisch zugewiesenen Variablen " viele Leute einfach sagen ... " huh ??? ".

Einige der Syntax Entscheidungen in C / C ++, dieses Problem zu verschärfen -. Zum Beispiel viele Leute denken, globale Variablen sind nicht „statisch“ wegen der Syntax unten

int var1; // Has global scope and static allocation
static int var2; // Has file scope and static allocation

int main() {return 0;}

Beachten Sie, dass das Schlüsselwort „statische“ in der Erklärung setzen oben verhindert var2 von den globalen Umfang haben. Dennoch hat die globale var1 statische Zuordnung. Dies ist nicht intuitiv! Aus diesem Grunde versuche ich nie das Wort „statisch“ zu verwenden, wenn Umfang der Beschreibung und stattdessen so sagenmething wie „Datei“ oder „Datei begrenzt“ scope. Allerdings nutzen viele Menschen den Begriff „statisch“ oder „static scope“ eine Variable zu beschreiben, die nur von einer Code-Datei zugegriffen werden kann. Im Zusammenhang mit der Lebenszeit, „statisch“ immer bedeutet die Variable beim Programmstart zugewiesen und freigegeben, wenn Programm beendet.

Einige Leute denken, diese Konzepte wie C / C ++ spezifisch. Sie sind nicht. Zum Beispiel zeigt die Python Probe unter alle drei Arten der Zuteilung (es gibt einige feine Unterschiede möglich in interpretierten Sprachen, die ich nicht in hier).

from datetime import datetime

class Animal:
    _FavoriteFood = 'Undefined' # _FavoriteFood is statically allocated

    def PetAnimal(self):
        curTime = datetime.time(datetime.now()) # curTime is automatically allocatedion
        print("Thank you for petting me. But it's " + str(curTime) + ", you should feed me. My favorite food is " + self._FavoriteFood)

class Cat(Animal):
    _FavoriteFood = 'tuna' # Note since we override, Cat class has its own statically allocated _FavoriteFood variable, different from Animal's

class Dog(Animal):
    _FavoriteFood = 'steak' # Likewise, the Dog class gets its own static variable. Important to note - this one static variable is shared among all instances of Dog, hence it is not dynamic!


if __name__ == "__main__":
    whiskers = Cat() # Dynamically allocated
    fido = Dog() # Dynamically allocated
    rinTinTin = Dog() # Dynamically allocated

    whiskers.PetAnimal()
    fido.PetAnimal()
    rinTinTin.PetAnimal()

    Dog._FavoriteFood = 'milkbones'
    whiskers.PetAnimal()
    fido.PetAnimal()
    rinTinTin.PetAnimal()

# Output is:
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is milkbones
# Thank you for petting me. But it's 13:05:02.256000, you should feed me. My favorite food is milkbones

Andere haben die breiten Striche ziemlich gut beantwortet, so dass ich in ein paar Details werfen.

  1. Stack und Heap muss nicht singulär sein. Eine gemeinsame Situation, in der Sie mehr als einen Stapel hat, wenn Sie mehr als einen Thread in einem Prozess haben. In diesem Fall ist jeder Thread hat seinen eigenen Stapel. Sie können auch mehr als einen Haufen haben, zum Beispiel einiger DLL-Konfigurationen in verschiedenen DLLs Zuweisen von verschiedenen Haufen führen können, weshalb es in der Regel eine schlechte Idee Speicher durch eine andere Bibliothek zugeordnet veröffentlichen.

  2. In C können Sie den Vorteil variabler Länge Zuweisung durch die Verwendung von erhalten alloca , die auf dem Stapel weist, wie zu alloc gegenüber, die auf dem Heap zuordnet. Dieser Speicher wird Ihre return-Anweisung nicht überleben, aber es ist nützlich für einen Scratch-Puffer.

  3. einen großen temporären Puffer auf Windows zu machen, dass Sie nicht viel nutzen aus ist nicht frei. Dies liegt daran, dass der Compiler eine Stapel Sonde Schleife erzeugen, die der Stapel besteht, um jedes Mal Ihre Funktion wird eingegeben aufgerufen wird sicher (da Windows eine einzelne Schutzseite am Ende des Stapels verwendet, um zu erkennen, wenn es um den Stapel wachsen muss. wenn Sie Speicher mehr als eine Seite aus dem Ende des Stapels zugreifen stürzen Sie). Beispiel:

void myfunction()
{
   char big[10000000];
   // Do something that only uses for first 1K of big 99% of the time.
}

Andere haben Ihre Frage direkt beantwortet, aber beim Versuch, den Stack und den Heap zu verstehen, ich denke, dass es hilfreich ist, das Speicherlayout eines traditionellen UNIX-Prozesses zu betrachten (ohne Gewinde und mmap()-basierten Verteilern). Die Memory Management Glossar Webseite hat ein Diagramm dieses Speicherlayout.

Der Stack und Heap sind traditionell an entgegengesetzten Enden des Verfahrens der virtuellen Adressraum befindet. Der Stapel wächst automatisch, wenn zugegriffen wird, bis zu einer Größe von dem Kernel gesetzt (die mit setrlimit(RLIMIT_STACK, ...) eingestellt werden können). Der Haufen wächst, wenn der Speicherzuordner den brk() oder sbrk() Systemaufruf ruft, mehr Seiten des physikalischen Speichers in den virtuellen Adressraum des Prozesses zuordnen.

In Systemen ohne virtuellen Speicher, wie zum Beispiel einige eingebettete Systeme, die gleiche grundlegende Layout gilt häufig, mit Ausnahme des Stack und Heap sind eine feste Größe. in anderen eingebetteten Systemen (wie beispielsweise solche auf Basis von Microchip PIC-Mikrocontroller) jedoch, der Programmstapel ein separater Speicherblock ist, der durch die Datenbewegungsanweisungen adressierbar ist nicht und kann nur indirekt durch Programmfluß Anweisungen modifiziert oder gelesen wird (Anruf, Rückkehr, etc.). Andere Architekturen wie Intel Itanium-Prozessoren, haben Sie mehrere Stapel . In diesem Sinne ist der Stapel ein Element der CPU-Architektur.

Der Stapel ist ein Abschnitt des Speichers, der über mehrere Schlüsselassemblersprachenanweisungen, wie beispielsweise ‚Pop‘ (entfernen und zurückgeben einen Wert aus dem Stack) und ‚Push‘ (Push-Wert auf den Stack) manipuliert werden kann, aber auch anrufen (ein Unterprogramm aufrufen - dies drückt die Adresse auf den Stapel zurück) und zurück (Rückkehr von einem Unterprogramm - dies die Adresse erscheint von dem Stapel und springt zu ihm). Es ist der Bereich des Speichers unterhalb des Stapelzeigerregister, die je nach Bedarf eingestellt werden kann. Der Stapel wird auch für die Weitergabe Argumente zu Subroutinen verwendet werden, und auch für die Werte in den Registern zu bewahren, bevor Subroutinen aufrufen.

Der Haufen ist ein Abschnitt des Speichers, der zu einer Anwendung durch das Betriebssystem gegeben wird, in der Regel durch eine Syscall wie malloc. Auf modernes OSes ist dieser Speicher eine Reihe von Seiten, die nur der Angerufene Prozess Zugriff hat.

Die Größe des Stapels wird zur Laufzeit ermittelt und in der Regel nicht wachsen, nachdem das Programm startet. In einem C-Programm muss der Stapel groß genug, um jede Variable innerhalb jeder Funktion deklariert zu halten. Der Haufen wird dynamisch wachsen wie nötig, aber das Betriebssystem macht schließlich den Anruf (es wird oft den Haufen von mehr wachsen als der Wert von malloc angefordert, so dass zumindest einige zukünftige mallocs nicht in den Kernel gehen müssen zurück zu mehr Speicher erhalten. Dieses Verhalten ist oft anpassbar)

Da Sie den Stapel reserviert haben, bevor Sie das Programm starten, müssen Sie nie malloc, bevor Sie den Stapel verwenden können, so dass ein leichter Vorteil gibt. In der Praxis ist es sehr schwer vorherzusagen, was schnell sein wird und was in modernen Betriebssystemen langsam sein, die virtuellen Speicher-Subsysteme haben, weil, wie die Seiten umgesetzt werden und wo sie gespeichert sind ein Implementierungsdetail ist.

Ich denke, dass viele andere Menschen, die Ihnen meistens in dieser Angelegenheit richtige Antworten gegeben haben.

Ein Detail, das aber versäumt wurde, ist, dass die „Halde“ soll wohl in der Tat des „freie Speicher“ bezeichnet werden. Der Grund für diesen Unterschied ist, dass der ursprüngliche freie Speicher mit einer Datenstruktur als bekannt implementiert wurde „binomische Haufen.“ Aus diesem Grunde, von den frühen Implementierungen von malloc Zuweisung () / free () war Zuteilung von einem Haufen. Allerdings sind in diesem modernen, die meisten freien Läden mit sehr aufwendigen Datenstrukturen implementiert, die nicht binomische Haufen.

Was ist ein Stapel?

Ein Stapel ist ein Stapel von Gegenständen, typischerweise eine, die ordentlich angeordnet ist.

 Gib Bild Beschreibung hier

  
    

Stacks in Rechenarchitekturen sind Speicherbereiche, wo Daten hinzugefügt oder entfernt wird in einer Last-in-first-out-Weise.
    In einer Multithread-Anwendung, wobei jeder Thread seinen eigenen Stapel haben.

  

Was ist ein Haufen?

Ein Haufen ist eine unordentliche Sammlung von Dingen planlos aufgestapelt.

 Gib Bild Beschreibung hier

  
    

Bei der Berechnung Architekturen der Heap ist ein Bereich, der dynamisch zugewiesenen Speicher, die automatisch durch das Betriebssystem oder die Speichermanager Bibliothek verwaltet wird.
    Speicher auf dem Heap zugeordnet ist, freigegeben, und regelmäßig während der Programmausführung der Größe verändert, und dies zu einem Problem genannt Fragmentierung führen kann.
    Fragmentation tritt auf, wenn Speicherobjekte zugeordnet sind, mit kleinen Zwischenräumen, die zu klein sind, um zusätzliche Speicherobjekte zu halten.
    Das Nettoergebnis ist ein Prozentsatz des Heap-Speicher, die nicht verwendbar für die weitere Speicherzuordnungen ist.

  

Beides zusammen

  
    

In einer Multi-Threaded-Anwendung, wobei jeder Thread seinen eigenen Stapel haben. Aber all die verschiedenen Threads den Heap teilen.
    Da die verschiedenen Threads den Heap in einer Multi-Thread-Anwendung gemeinsam nutzen, bedeutet dies auch, dass es eine gewisse Koordination zwischen den Fäden sein, damit sie nicht versuchen, das gleiche Stück (e) von Speicher im Heap für Zugriff und Manipulation an zur gleichen Zeit.

  

Welche ist schneller - der Stapel oder Haufen? Und warum?

  
    

Der Stapel ist viel schneller als die Halde.
    Dies ist wegen der Art und Weise, dass der Speicher auf dem Stack zugeordnet ist.
    Speicher auf dem Stapel Zuteilen ist so einfach wie die Stapelzeiger nach oben bewegt wird.

  

Für neue Leute Programmierung, es ist wahrscheinlich eine gute Idee, um den Stapel zu verwenden, da es einfacher ist.
Da der Stapel klein ist, würden Sie wollen, es zu benutzen, wenn Sie genau wissen, wie viel Speicher Sie für Ihre Daten benötigen, oder wenn Sie die Größe Ihrer Daten wissen, ist sehr klein.
Es ist besser, den Haufen zu verwenden, wenn Sie wissen, dass Sie für Ihre Daten viel Speicherplatz benötigen, oder Sie sind einfach nicht sicher, wie viel Speicher Sie (wie mit einem dynamischen Array) benötigen.

Java-Speichermodell

 Gib Bild Beschreibung hier

Der Stapel ist der Bereich des Speichers, in dem lokale Variablen (einschließlich der Verfahrensparameter) gespeichert sind. Wenn es darum geht Variablen zu widersprechen, sind diese lediglich Referenzen (Zeiger) auf die tatsächlichen Objekte auf dem Heap.
Jedes Mal, wenn ein Objekt instantiiert wird, wird ein Stück von Heapspeicher beiseite legt die Daten (Zustand) des Objekts zu halten. Da Objekte andere Objekte enthalten können, können einige dieser Daten in der Tat halten Verweise auf diese verschachtelte Objekte.

Sie können mit dem Stapel einige interessante Dinge tun. Zum Beispiel haben Sie Funktionen wie alloca (vorausgesetzt, Sie vorbei an den reichlich Warnungen über bekommen kann seine Verwendung), die eine Form von malloc ist, die speziell den Stapel verwendet, nicht die Haufen, für Speicher.

Wie gesagt, Stack-basierte Speicherfehler sind nur einige der schlimmsten, die ich erlebt habe. Wenn Sie Heap-Speicher verwenden, und Sie überschreiten die Grenzen des zugewiesenen Block, haben Sie eine gute Chance, einen Segmentfehler auszulösen. (Nicht 100%: Ihr Block übrigens angrenzt eine andere sein kann, die Sie vorher zugewiesen haben.) Aber da Variablen auf dem Stapel erstellt werden immer zusammenhängend miteinander, kann außerhalb der Grenzen Schreiben des Wertes einer anderen Variablen ändern. Ich habe gelernt, dass, wenn ich das Gefühl, dass mein Programm die Gesetze der Logik aufgehört hat zu gehorchen, ist es wahrscheinlich Pufferüberlauf.

Einfach gesagt, ist der Stapel, wo lokale Variablen erstellt bekommen. Auch jedes Mal, das ein Unterprogramm den Programmzähler (Zeiger auf die nächste Maschinenbefehl) aufrufen und alle wichtigen Register, und manchmal sind die Parameter auf den Stapel geschoben bekommen. Dann alle lokalen Variablen innerhalb der Unterroutine werden auf den Stapel geschoben (und von dort verwendet wird). Wenn das Unterprogramm beendet ist, wird knallt all das Zeug aus dem Stapel zurück. Der PC und die Datenregister bekommt und wieder, wo es war, als es umgestülpt worden ist, so dass Ihr Programm auf seiner fröhlichen Art und Weise gehen.

Der Haufen ist der Speicherbereich, der dynamischen Speicherzuordnungen werden aus (explicit „neu“ oder „zuweisen“ Anrufe) gemacht. Es ist eine spezielle Datenstruktur, die den Überblick über Speicherblöcke unterschiedlicher Größe und ihre Verteilung Status behalten kann.

In „klassischen“ Systemen RAM wurde so ausgelegt, dass der Stapelzeiger gestartet am unteren Rande des Speichers aus, begann der Heapzeiger an der Spitze, und sie wuchs gegeneinander. Wenn sie sich überlappen, sind Sie aus dem RAM. Das funktioniert nicht mit modernen Multi-Threaded OSes though. Jeder Thread hat seinen eigenen Stapel haben, und die können dynamicly erstellt bekommen.

Von WikiAnwser.

Stapel

Wenn eine Funktion oder ein Verfahren, eine andere Funktion aufruft, die abwechselnd eine andere Funktion aufruft, etc., um die Ausführung aller dieser Funktionen suspendiert bleibt, bis die letzte Funktion ihren Wert zurückgibt.

Diese Kette von suspendierten Funktion aufruft ist der Stapel, weil Elemente in dem Stapel (Funktionsaufrufe) voneinander abhängig ist.

Der Stapel ist wichtig, in Ausnahmebehandlung und Gewindeausführungen zu berücksichtigen.

Heap

Der Haufen ist einfach der Speicher von Programmen verwendet Variablen zu speichern. Element des Haufens (Variablen) hat keine Abhängigkeiten untereinander und kann immer zufällig jederzeit zugegriffen werden kann.

Stapel

  • Sehr schneller Zugriff
  • Sie müssen Variablen nicht explizit de-allocate
  • Space effizient von der CPU verwaltet wird, Speicher wird nicht fragmentiert werden
  • Lokale Variablen nur
  • Begrenzung Stackgröße (OS-abhängig)
  • Variablen können nicht geändert werden

Heap

  • Variablen global zugegriffen werden kann
  • Keine Begrenzung auf Speichergröße
  • (relativ) langsamer Zugang
  • Keine garantiert effiziente Raumnutzung, Speicher im Laufe der Zeit fragmentiert werden können als Speicherblöcke zugeordnet sind, dann befreit
  • Sie müssen Speicher verwalten (Sie sind verantwortlich für die Zuteilung und Freigabe-Variablen)
  • Variablen können geändert werden mit realloc ()

OK einfach und kurz gesagt, sie bedeuten bestellt und nicht bestellt ...

Stapel : In Stapel Artikel, die Dinge auf der Oberseite jeder-andere bekommen, bedeutet, werde schneller und effizienter verarbeitet werden ...

Es gibt also immer ein Index, der den bestimmten Punkt zu Punkt, auch werde schneller verarbeiten, gibt es Beziehungen zwischen den als auch Einzelteile! ...

Heap : Kein Auftrag, Verarbeitung würde langsamer sein und Werte werden zusammen mit keiner bestimmten Reihenfolge oder Index vermasseln ... gibt es zufällig und es gibt keine Beziehung zwischen ihnen ... so Ausführung und Nutzungszeit könnte sein, die sich ...

Ich schaffe auch das Bild unten zu zeigen, wie sie aussehen kann:

 image description hier

Kurz notiert

Ein Stapel wird für statische Speicherzuweisung und ein Heap für dynamische Speicherzuweisung verwendet, sowohl im RAM des Computers gespeichert.


Im Detail

Der Stapel

Der Stapel ein „LIFO“ ist (last in, first out) Datenstruktur, die durch die CPU ziemlich eng verwaltet und optimiert. Jedes Mal, wenn eine Funktion eine neue Variable deklariert wird „gedrückt“ auf den Stapel. Dann jedes Mal, wenn eine Funktion beendet wird, alle Variablen geschoben auf den Stapel von dieser Funktion wird befreit (dh, sie werden gelöscht). Sobald ein Stapel Variable freigegeben wird, dass der Bereich des Speichers für andere Stack-Variablen verfügbar wird.

Der Vorteil, den Stapel der Verwendung von Variablen zu speichern, ist, dass der Speicher für Sie verwaltet. Sie müssen nicht von Hand Speicher zuweisen, oder es kostenlos, wenn Sie es nicht mehr benötigen. Was mehr ist, weil die CPU so effizient Stapelspeicher organisiert, Lesen und Schreiben von Variablen zu stapeln ist sehr schnell.

Mehr finden Sie hier .


Die Heap

Der Haufen ist eine Region des Arbeitsspeicher Ihres Computers, die nicht automatisch für Sie verwaltet wird, und ist nicht so fest von der CPU gesteuert. Es ist ein weiterer frei schwebender Bereich des Speichers (und größer). So weisen Speicher auf dem Heap, müssen Sie malloc () oder calloc () verwenden, die eingebaut sind C-Funktionen. Sobald Sie Speicher auf dem Heap zugewiesen haben, sind Sie verantwortlich für die freie Verwendung von (), dass der Speicher freizugeben, wenn Sie es nicht mehr benötigen.

Wenn Sie dies nicht tun, wird Ihr Programm haben, was als ein Speicherleck bekannt ist. Das heißt, Speicher auf dem Heap noch beiseite werden (und nicht an anderen Prozessen zur Verfügung steht). Wie wir in der Debug-Abschnitt sehen werden, ist es ein Tool namens Valgrind , die Sie Speicher erkennen kann helfen Leckagen.

Im Gegensatz zu dem Stapel, die Heap-Größe nicht Beschränkungen für variable Größe hat (abgesehen von den offensichtlichen körperlichen Einschränkungen Ihres Computers). Heap-Speicher ist etwas langsamer aus gelesen und geschrieben, weil ein Zeiger zu verwenden, hat auf der Heap-Speicher zuzugreifen. Wir werden in Kürze über Zeiger sprechen.

Im Gegensatz zu dem Stapel, Variablen auf dem Heap erstellt wird, sind von jeder Funktion, überall in Ihrem Programm. Heap-Variablen sind im Wesentlichen ein global agierendes Unternehmen.

Mehr finden Sie hier .


Variablen auf dem Stack zugeordnet ist, direkt mit dem Speicher und Zugriff auf diesen Speicher gespeichert ist sehr schnell, und ihre Aufteilung wird behandelt, wenn das Programm kompiliert wird. Wenn eine Funktion oder ein Verfahren ruft eine andere Funktion, die abwechselnd eine andere Funktion aufruft, usw., bleibt die Ausführung aller dieser Funktionen angehalten, bis die letzte Funktion ihren Wert zurückgibt. Der Stapel wird immer in einer LIFO-Reihenfolge reserviert, der zuletzt reservierten Block immer der nächste Block befreit werden. Dies macht es wirklich einfach den Überblick über den Stapel zu halten, einen Block vom Stapel zu befreien ist nichts anderes als einen Zeiger eingestellt wird.

Variablen auf dem Heap zugewiesen haben ihre Speicher zur Laufzeit zugeordnet und diesen Zugriff auf den Speicher ist etwas langsamer, aber die Heap-Größe nur durch die Größe des virtuellen Speichers begrenzt ist. Elemente des Haufens haben keine Abhängigkeiten untereinander und können immer zufällig jederzeit zugegriffen werden kann. Sie können einen Block jederzeit zuweisen und es jederzeit frei. Dies macht es sehr viel komplexer, um zu verfolgen, welche Teile des Heap zugewiesen werden oder frei zu einem bestimmten Zeitpunkt.

 Gib Bild Beschreibung hier

Sie können den Stapel verwenden, wenn Sie genau wissen, wie viele Daten Sie vor der Kompilierung t zuweisen müssenime, und es ist nicht zu groß. Sie können den Heap verwenden, wenn Sie nicht genau wissen, wie viele Daten Sie zur Laufzeit benötigt, oder wenn Sie eine Menge Daten zuweisen müssen.

In einer Multi-Threaded-Situation jeder Thread seine eigenen völlig unabhängig Stapel hat, aber sie werden die Haufen teilen. Der Stapel ist Thread spezifisch und der Haufen ist anwendungsspezifisch. Der Stapel ist wichtig, in Ausnahmebehandlung und Gewindeausführungen zu berücksichtigen.

Jeder Thread bekommt einen Stapel, während es nur ein Haufen für die Anwendung in der Regel ist (obwohl es nicht ungewöhnlich, dass mehrere Haufen für verschiedene Arten von Zuordnung haben).

 Gib Bild Beschreibung hier

Zur Laufzeit, wenn die Anwendung mehr Heap benötigt, kann sie Speicher aus freien Speicher zuweisen und wenn der Stapelspeicher benötigt, kann sie Speicher aus freien Speicher für die Anwendung zugewiesenen Speicher zuzuweisen.

Auch, genauer gegeben hier und hier .


Jetzt kommt auf Ihre Frage der Antworten .

  

Inwieweit werden sie von den OS oder Language Runtime gesteuert?

Das O ordnet den Stapel für jeden Systemebene-Thread, wenn der Thread erstellt wird. Typischerweise ist das O von der Sprache Laufzeit aufgerufen wird, um den Heap für die Anwendung zuzuordnen.

Weitere hier .

  

Was ist ihr Anwendungsbereich?

Bereits oben gegeben.

  

"können Sie den Stapel verwenden, wenn Sie genau wissen, wie viele Daten Sie vor der Kompilierung zuweisen müssen, und es ist nicht zu groß. Sie können den Heap verwenden, wenn Sie nicht genau wissen, wie viele Daten Sie benötigen Laufzeit oder wenn Sie eine Menge Daten. "

zuzuteilen

Mehr kann in hier .

  

Was die Größe eines jeden von ihnen bestimmt?

Die Größe des Stapels wird von OS , wenn ein Thread erstellt wird. Die Größe des Haufens auf Start der Anwendung festgelegt ist, aber es kann wachsen als Speicherplatz benötigt wird (die Zuordner mehr Speicher vom Betriebssystem anfordert).

  

Was macht man schneller?

Stack-Allokation ist viel schneller, da alle es wirklich tut, ist der Stapelzeiger bewegen. Speicherpools verwenden, können Sie eine vergleichbare Leistung aus Heapzuordnung, aber das kommt mit einem geringen zusätzlichen Komplexität und seine eigenen Kopfschmerzen.

Auch Stapel vs. Halde ist nicht nur eine Leistung Betracht; es sagt Ihnen auch viel über die erwartete Lebensdauer von Objekten.

Details können von hier werden .

In den 1980er Jahren propagierten UNIX wie Hasen mit großen Unternehmen, die ihre eigenen Rollen. Exxon hatte man als zur Geschichte verloren Dutzende von Markennamen haben. Wie Speicher wurde im Ermessen der vielen Implementierer war gelegt.

Ein typisches C-Programm wurde flach in Speicher gelegt mit eine Gelegenheit, durch Änderung des brk () Wert zu erhöhen. Typischerweise war die HEAP knapp unter diesem Wert brk und die Erhöhung brk erhöht die Menge des verfügbaren Heap.

Die einzelnen Stapel waren typischerweise unter HEAP einen Bereich, der eine Fläche des Speichers war nichts von Wert, bis der Anfang des nächsten festen Block des Speichers enthält. Dieser nächste Block war oft Code, der durch Stapel Daten überschrieben werden in einem der berühmten Hacks seiner Zeit.

Ein typischer Speicherblock war BSS (ein Block von Nullwerten) die versehentlich nicht in einem Herstellerangebot auf Null gesetzt. Ein anderer war DATA initialisierten Werte enthalten, einschließlich Strings und Zahlen. Ein drittes war CODE enthält CRT (C-Laufzeit), Haupt, Funktionen und Bibliotheken.

Das Aufkommen des virtuellen Speichers in UNIX ändert sich viele der Einschränkungen. Es gibt keinen objektiven Grund, warum diese Blöcke zusammenhängend sein müssen, oder eine feste Größe oder bestellt nun eine besondere Art und Weise. Natürlich, bevor UNIX war Multics, die von diesen Einschränkungen nicht betroffen. Hier ist ein schematischer einen des Speicherlayouts jener Zeit zeigt.

Ein typischer Stil der 1980er Jahre UNIX C-Programmspeicher Layout

Stapel , heap und Daten jeden Prozess in der virtuellen Speicher:

Ein paar Cent: Ich denke, es wird gut sein Gedächtnis grafische zu zeichnen und einfacher:


Arrows - zeigen, wo wachsen Stack und Heap, Prozess-Stack-Größe hat Grenze, definierte in O, Thread-Stapelgröße Grenzen, die durch Parameter in Thread-API erstellen in der Regel. Heap in der Regel durch den Prozess maximale Größe des virtuellen Speichers, für 32 Bit 2-4 GB beispielsweise begrenzen.

So einfache Art und Weise. Prozess-Heap für den Prozess allgemein ist und alle Innengewinde, mit für die Speicherzuordnung gemeinsam Fall mit so etwas wie malloc ()

Stack ist ein schneller Speicher für Speicher gemeinsam Fall Funktion Rückkehr Zeiger und Variablen als Parameter in Funktionsaufruf verarbeitet, lokale Funktionsvariablen.

Da einige Antworten Erbsenzählerei ging, werde ich mein Scherflein beitragen.

Überraschenderweise hat niemand erwähnt, dass mehrere (dh nicht von dem Betriebssystem OS-Level-Threads auf die Anzahl bezogen) Aufruflisten gefunden werden, sind nicht nur in exotischen Sprachen (Postscript) oder Plattformen (Intel Itanium), sondern auch in < a href = "http://en.wikipedia.org/wiki/Fiber_(computer_science)" rel = "nofollow noreferrer"> Fasern , grüne Fäden und einige Implementierungen von Koroutinen .

Fasern, grünen Fäden und Koroutinen sind in vielerlei Hinsicht ähnlich, was zu viel Verwirrung führt. Der Unterschied zwischen den Fasern und grünen Fäden ist, dass die frühere Nutzung kooperatives Multitasking, während die letzteren entweder kooperativ oder preemptive einem Merkmal kann (oder sogar beide). siehe für die Unterscheidung zwischen den Fasern und Koroutinen, hier .

In jedem Fall ist der Zweck der beiden Fasern, Fäden und grünen Koroutinen ausführt gleichzeitig mehrere Funktionen haben, aber nicht parallel (siehe diese Frage SO für die Unterscheidung ) innerhalb eines einzelnen OS-Level-Thread, Steuerung überträgt hin und her voneinander in einer organisierten Art und Weise .

Wenn Fasern, grünen Fäden oder Koroutinen verwenden, können Sie in der Regel haben einen separaten Stapel pro Funktion. (Technisch gesehen, nicht nur ein Stapel, sondern ein ganzer Kontext der Ausführung ist pro Funktion. Am wichtigsten ist, CPU-Register). Für jeden Faden dort ist so viele Stapel als da sind gleichzeitig Funktionen ausführen, und der Faden wird zwischen jeder Schaltfunktion ausführen nach der Logik des Programms. Wenn eine Funktion zu Ende läuft, wird sein Stapel zerstört. Also, die Anzahl und die Lebensdauer des Stacks ist dynamisch und sind nicht durch die Anzahl der OS-Ebene Threads bestimmt!

Beachten Sie, dass ich sagte: „ in der Regel einen separaten Stapel pro Funktion haben“. Es sind beide stackful und stackless Implementierungen von couroutines. Am bemerkenswertesten stackful C ++ Implementierungen sind Boost.Coroutine und Microsoft PPL 's async/await. (Jedoch, C ++ 's resumable Funktionen (aka "async und await"), die auf C ++ 17 vorgeschlagen wurden, sind wahrscheinlich stackless Koroutinen verwenden.)

Fasern Vorschlag an die C ++ Standard-Bibliothek ist in Vorbereitung. Auch dort sind einige Drittanbieter Bibliotheken . Grüne Themen sind sehr beliebt in Sprachen wie Python und Ruby.

Ich habe etwas zu teilen, obwohl die wichtigsten Punkte bereits abgedeckt sind.

Stapel

  • Sehr schneller Zugriff.
  • im RAM gespeichert.
  • Funktionsaufrufe werden hier zusammen mit den lokalen Variablen und Parameter der Funktion übergeben geladen.
  • Der Raum wird befreit automatisch, wenn Programm aus einem Rahmen geht.
  • Gespeicherte in sequentiellen Speichern.

Heap

  • Langsamer Zugriff vergleichsweise stapeln.
  • im RAM gespeichert.
  • Dynamisch erstellten Variablen hier gespeichert, die später benötigt den zugewiesenen Speicher nach dem Gebrauch zu befreien.
  • Gespeicherte überall dort, wo die Speicherzuordnung wird, immer durch Zeiger zugegriffen getan.

Interessante Anmerkung:

  • Sollte die Funktionsaufrufe hatte im Heap gespeichert worden sind, wäre es hatte in 2 unordentlich Punkte geführt:
    1. Durch sequentielle Speicherung in Stapeln, die Ausführung ist schneller. Lagerung in Haufen in großen Zeitaufwand ergeben hätte somit das ganze Programm durchführen zu machen langsamer.
    2. Sind Funktionen in Heap (unordentlich Speicherung von Zeigern gezeigt) gespeichert wurden, hat es gäbe keine Möglichkeit, auf die Anrufer-Adresse zurückzukehren (die Stapel aufgrund sequentieller Speicherung im Speicher gibt).

Viele Antworten sind richtig als Konzepte, aber wir müssen beachten, dass ein Stapel von der Hardware (das heißt Mikroprozessor) benötigt wird, rufen Subroutinen zu ermöglichen (CALL in Assembler-Sprache ..). (OOP Jungs nennen es Methoden )

Auf dem Stapel Sie zurückkommen Adressen speichern und rufen → Push / ret → Pop ist direkt in der Hardware verwaltet werden.

Sie den Stapel verwenden können Parameter übergeben .. auch wenn es langsamer als Register (wäre ein Mikroprozessor Guru sagen oder ein gutes 1980ern BIOS Buch ...)

  • Ohne Stapel nicht Mikroprozessor arbeiten kann. (Wir ein Programm sich nicht vorstellen kann, auch in Assemblersprache, ohne Subroutinen / Funktionen)
  • Ohne den Haufen es kann. (Ein Assembler-Sprache-Programm kann ohne Arbeit, wie der Haufen ein OS-Konzept ist, wie malloc, dass ein O / Lib Anruf ist.

Stack-Nutzung ist schneller als:

  • Ist Hardware und sogar Push / Pop sehr effizient sind.
  • malloc erfordert die Eingabe Kernel-Modus, verwenden Sie lock / Semaphore (oder andere Synchronisations Primitiven) einen Code ausführt und einige Strukturen verwalten benötigt Spur der Zuteilung zu halten.

Wow! So viele Antworten, und ich glaube nicht, einer von ihnen haben es richtig ...

1) Wo und was sind sie (physisch in einem realen Speicher des Computers)?

Der Stapel ist Speicher, der als die höchste Speicheradresse zu Ihrem Programm Bild zugeordnet beginnt und dann von dort in Wert zu verringern. Es ist reserviert für genannt Funktionsparameter und für alle temporären Variablen in Funktionen verwendet.

Es gibt zwei Haufen: Öffentliche und private

.

Der private Haufen beginnt auf einer 16-Byte-Grenze (für 64-Bit-Programme) oder eine 8-Byte-Grenze (für 32-Bit-Programme) nach der letzten Byte-Code in Ihrem Programm, und steigt dann in Wert von dort . Es ist auch der Standard-Heap.

genannt

Wenn die privaten Haufen zu groß werden wird es den Stapelbereich überlappt, wie der Stapel den Heap überlappen, wenn sie zu groß werden. Da der Stapel mit einer höheren Adresse beginnt und bahnt sich seinen Weg nach unten zu niedrigeren Adresse, mit der richtigen Hacking können Sie den Stapel machen bekommen, so groß, dass es den privaten Heap Bereich überrannt und den Code-Bereich überlappen. Der Trick ist dann genug von dem Codebereich zu überlappen, die Sie in den Code Haken können. Es ist ein wenig schwierig zu tun, und Sie einen Programmabsturz riskieren, aber es ist einfach und sehr effektiv.

Der öffentliche Haufen liegt in einem eigenen Speicherbereich außerhalb des Programms Bildraumes. Es ist dieser Speicher, der auf die Festplatte abgeschöpft werden, wenn Speicherressourcen knapp werden.

2) Inwieweit werden sie von den OS oder Language Runtime gesteuert?

Der Stapel vom Programmierer gesteuert wird, wird der private Haufen vom Betriebssystem verwaltet und die Öffentlichkeit Haufen wird von niemandem kontrolliert, weil es ein OS-Service ist -. Sie machen Anfragen und sie entweder gewährt oder verweigert

2b) Was ist ihr Anwendungsbereich?

Sie sind alle global auf das Programm, aber ihr Inhalt kann private, öffentliche oder global sein.

2c) Was die Größe eines jeden von ihnen bestimmt?

Die Größe des Stapels und der private Heap werden vom Compiler Laufzeitoptionen bestimmt. Der öffentliche Heap wird zur Laufzeit initialisiert eine Größe Parameter verwendet wird.

2d) Was macht man schneller?

Sie sind nicht schnell zu sein entworfen, sind sie nützlich sein entworfen. Wie der Programmierer nutzt sie bestimmt, ob sie „schnell“ oder „langsam“ sind

REF:

https://norasandler.com/2019/02/ 18 / Write-a-Compiler-10.html

https://docs.microsoft. com / en-us / windows / Desktop / api / heapapi / nf-heapapi-GetProcessHeap

https://docs.microsoft. com / en-us / windows / Desktop / api / heapapi / nf-heapapi-HeapCreate

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