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)

56voto

Abrar Jahin Punkte 13034

Kurz gesagt

Ein Stack wird für die statische Speicherzuweisung und ein Heap für die dynamische Speicherzuweisung verwendet, die beide im RAM des Computers gespeichert sind.


Im Detail

Der Stack

Der Stack ist eine "LIFO" (last in, first out) Datenstruktur, die vom CPU sehr genau verwaltet und optimiert wird. Jedes Mal, wenn eine Funktion eine neue Variable deklariert, wird sie auf den Stack "geschoben". Dann werden jedes Mal, wenn eine Funktion beendet wird, alle Variablen, die von dieser Funktion auf den Stack geschoben wurden, freigegeben (das heißt, sie werden gelöscht). Sobald eine Stack-Variable freigegeben ist, wird dieser Speicherbereich für andere Stack-Variablen verfügbar.

Der Vorteil der Verwendung des Stacks zur Speicherung von Variablen besteht darin, dass der Speicher für Sie verwaltet wird. Sie müssen keinen Speicher manuell zuweisen oder freigeben, wenn Sie ihn nicht mehr benötigen. Darüber hinaus, da der CPU den Stackspeicher so effizient organisiert, ist das Lesen von und Schreiben auf Stack-Variablen sehr schnell.

Weitere Informationen finden Sie hier.


Der Heap

Der Heap ist ein Bereich des Speichers Ihres Computers, der nicht automatisch für Sie verwaltet wird und nicht so eng vom CPU verwaltet wird. Es handelt sich um einen freischwebenden Speicherbereich (und ist größer). Um Speicher im Heap zuzuweisen, müssen Sie malloc() oder calloc() verwenden, die eingebaute C-Funktionen sind. Sobald Sie Speicher im Heap zugewiesen haben, sind Sie dafür verantwortlich, diesen Speicher mit free() freizugeben, sobald Sie ihn nicht mehr benötigen.

Wenn Sie dies nicht tun, wird Ihr Programm einen sogenannten Speicherleck haben. Das bedeutet, dass Speicher im Heap weiterhin reserviert wird (und anderen Prozessen nicht zur Verfügung steht). Wie wir im Abschnitt zur Fehlersuche sehen werden, gibt es ein Tool namens Valgrind, das Ihnen helfen kann, Speicherlecks zu erkennen.

Im Gegensatz zum Stack gibt es auf dem Heap keine Größenbeschränkungen für die Variablengröße (abgesehen von den offensichtlichen physikalischen Grenzen Ihres Computers). Heap-Speicher ist etwas langsamer zu lesen und zu schreiben, da man Zeiger verwenden muss, um auf den Speicher im Heap zuzugreifen. Über Zeiger werden wir gleich sprechen.

Im Gegensatz zum Stack sind auf dem Heap erstellte Variablen von jeder Funktion, überall in Ihrem Programm zugänglich. Heap-Variablen haben im Wesentlichen einen globalen Geltungsbereich.

Weitere Informationen finden Sie hier.


Auf dem Stack allokierte Variablen werden direkt im Speicher gespeichert, und der Zugriff auf diesen Speicher ist sehr schnell. Der Allocator wird während der Programmkompilierung behandelt. Wenn eine Funktion oder eine Methode eine andere Funktion aufruft, die wiederum eine andere Funktion aufruft usw., bleibt die Ausführung all dieser Funktionen ausgesetzt, bis die allerletzte Funktion ihren Wert zurückgibt. Der Stack ist immer in LIFO-Reihenfolge reserviert, der zuletzt reservierte Block ist immer der nächste Block, der freigegeben wird. Es ist also sehr einfach, den Stack zu verwalten, das Freigeben eines Blocks vom Stack bedeutet nichts anderes als das Anpassen eines Zeigers.

Auf dem Heap allokierte Variablen haben ihren Speicher zur Laufzeit zugewiesen, und der Zugriff auf diesen Speicher ist etwas langsamer, aber die Heap-Größe ist nur durch die Größe des virtuellen Speichers begrenzt. Elemente des Heaps haben keine Abhängigkeiten voneinander und können jederzeit beliebig zufällig zugegriffen werden. Sie können zu jedem Zeitpunkt einen Block zuweisen und ihn zu jedem Zeitpunkt freigeben. Daher ist es viel komplizierter, den Überblick darüber zu behalten, welche Teile des Heaps zu einem bestimmten Zeitpunkt belegt oder freigegeben sind.

Gib hier eine Bildbeschreibung ein

Sie können den Stack verwenden, wenn Sie genau wissen, wie viele Daten Sie vor der Kompilierungszeit zuweisen müssen und sie nicht zu groß sind. Sie können den Heap verwenden, wenn Sie nicht genau wissen, wie viele Daten Sie zur Laufzeit benötigen werden oder wenn Sie eine große Menge an Daten zuweisen müssen.

In einer mehrfädigen Situation hat jeder Thread seinen eigenen vollständig unabhängigen Stack, aber sie teilen sich den Heap. Der Stack ist fadenspezifisch, und der Heap ist anwendungsbezogen. Der Stack ist wichtig bei Ausnahmebehandlungen und Threadausführungen.

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

Gib hier eine Bildbeschreibung ein

Zur Laufzeit, wenn die Anwendung mehr Heap benötigt, kann sie Speicher aus freiem Speicher zuweisen, und wenn der Stack Speicher benötigt, kann er Speicher aus freiem Speicher zuweisen, der für die Anwendung allokiert wurde.

Noch weitere Details finden Sie hier und hier.


Kommen Sie nun zu den Antworten Ihrer Fragen.

In welchem Umfang werden sie vom Betriebssystem oder der Sprachlaufzeitkontrolle beeinflusst?

Das Betriebssystem reserviert den Stack für jeden Systemthread auf Systemebene, wenn der Thread erstellt wird. Typischerweise ruft die Sprachlaufzeit das Betriebssystem auf, um den Heap für die Anwendung zuzuweisen.

Weitere Informationen finden Sie hier.

Was ist ihr Geltungsbereich?

Bereits oben angegeben.

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

Es gibt weitere Informationen hier.

Was bestimmt ihre Größe?

Die Größe des Stacks wird vom Betriebssystem festgelegt, wenn ein Thread erstellt wird. Die Größe des Heaps wird beim Start der Anwendung festgelegt, kann jedoch bei Bedarf wachsen (der Allocator fordert mehr Speicher vom Betriebssystem an).

Was macht einen davon schneller?

Die Stackzuweisung ist viel schneller, da alles, was es wirklich tut, das Verschieben des Stack-Zeigers ist. Durch die Verwendung von Speicherpools können Sie eine vergleichbare Leistung aus der Heapzuweisung erhalten, aber dies bringt eine leichte zusätzliche Komplexität und eigene Kopfschmerzen mit sich.

Außerdem ist Stapel gegenüber Heap nicht nur eine Überlegung in Bezug auf die Leistung; es sagt Ihnen auch viel über die erwartete Lebensdauer von Objekten aus.

Weitere Details finden Sie hier.

55voto

Alireza Punkte 92209

OK, einfach und in kurzen Worten bedeuten sie geordnet und nicht geordnet...!

Stack: In einem Stapel werden Elemente übereinander gestapelt, was bedeutet, dass die Verarbeitung schneller und effizienter erfolgt!...

Es gibt also immer einen Index, um das spezifische Element zu zeigen, außerdem wird die Verarbeitung schneller sein, es besteht auch eine Beziehung zwischen den Elementen!...

Heap: Keine Ordnung, die Verarbeitung wird langsamer sein und die Werte sind durcheinander und ohne spezifische Reihenfolge oder Index... sie sind zufällig und es besteht keine Beziehung zwischen ihnen... daher könnten sich Ausführungs- und Verwendungsdauer unterscheiden...

Ich habe auch das untenstehende Bild erstellt, um zu zeigen, wie sie aussehen könnten:

Bildbeschreibung eingeben

0 Stimmen

Was bedeuten "Beziehung" und "Reihenfolge" in diesem Zusammenhang?

47voto

Yousha Aleayoub Punkte 3778

Stack, Heap und Daten jedes Prozesses im virtuellen Speicher:

Stack, Heap und statische Daten

37voto

jlettvin Punkte 1081

In den 1980er Jahren verbreitete sich UNIX wie Kaninchen, wobei große Unternehmen ihre eigenen Systeme einführten. Exxon hatte eines, genauso wie Dutzende von Markennamen, die in der Geschichte verloren gegangen sind. Wie der Speicher angelegt wurde, lag im Ermessen der vielen Implementierer.

Ein typisches C-Programm wurde flach im Speicher angelegt mit der Möglichkeit, den Wert von brk() zu ändern. Typischerweise lag der HEAP knapp unter diesem brk-Wert und durch Erhöhung von brk wurde der verfügbare Heap vergrößert.

Der einzige STACK war typischerweise ein Bereich unter dem HEAP, der ein Speicherblock war, der bis zum oberen Rand des nächsten festen Speicherblocks nichts Wertvolles enthielt. Dieser nächste Block war oft der CODE, der durch Stackdaten überschrieben werden konnte bei einem der berühmten Hacks dieser Ära.

Ein typischer Speicherblock war der BSS (ein Block mit Nullwerten), der versehentlich nicht nullgesetzt wurde bei einem Angebot eines Herstellers. Ein anderer war DATA, der initialisierte Werte enthielt, einschließlich Strings und Zahlen. Ein dritter war CODE, der CRT (C-Laufzeitumgebung), main, Funktionen und Bibliotheken enthielt.

Das Aufkommen von virtuellem Speicher in UNIX änderte viele der Einschränkungen. Es gibt keinen objektiven Grund, warum diese Blöcke nicht mehr zusammenhängend sein müssen, oder feste Größe haben müssen, oder auf eine bestimmte Weise angeordnet sein müssen. Natürlich gab es vor UNIX Multics, das nicht unter diesen Einschränkungen litt. Hier ist eine schematische Darstellung eines der Speicherlayouts aus dieser Ära.

Ein typisches Speicherlayout für ein UNIX C-Programm der 1980er Jahre

28voto

Maxim Akristiniy Punkte 2061

Ein paar Gedanken: Ich denke, es wird gut sein, das Gedächtnis grafisch und einfacher zu zeichnen:

Das ist meine Vorstellung vom Prozessgedächtnisaufbau mit Vereinfachung zur besseren Verständlichkeit dessen, was passiert

Pfeile - zeigen, wo Stack und Heap wachsen, die Prozessstapelgröße hat ein Limit, das im Betriebssystem definiert ist, die Grenzen der Thread-Stackgröße werden normalerweise durch Parameter in der Thread-Erstellungs-API festgelegt. Der Heap wird normalerweise durch die maximale virtuelle Speichergröße des Prozesses begrenzt, für 32-Bit z.B. 2-4 GB.

Also auf einfache Weise: Der Prozess-Heap ist allgemein für den Prozess und alle Threads darin, der in der Regel für die Speicherzuweisung im Allgemeinen mit etwas Ähnlichem wie malloc() verwendet wird.

Der Stack ist schneller Speicher zum Speichern von Funktionen, die normalerweise Rückgabepunkte und Variablen verarbeiten, die als Parameter in Funktionsaufrufen und lokalen Funktionsvariablen verwendet werden.

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