Verwendung von Stack vs. Heap-Speicherzuweisung in C++

Jinku Hu 12 Oktober 2023
Verwendung von Stack vs. Heap-Speicherzuweisung in C++

In diesem Artikel werden verschiedene Methoden zur Verwendung der Stack- oder Heap-Speicherzuordnung in C++ erläutert.

Unterschied zwischen Stack- und Heap-Speicher in C++

Wenn wir die Speicherkonzepte diskutieren möchten, denken Sie am besten an Systeme, auf denen die gängigsten Benutzerprogramme laufen. Die meisten Benutzerprogramme werden in einer Betriebssystemumgebung ausgeführt, die für uns Hardwareressourcen verwaltet und verschiedene Aufgaben übernimmt, die für ein Benutzerprogramm zu komplex oder ineffizient wären. Eine dieser Aufgaben besteht darin, den Hardwarespeicher direkt zu verwalten. Somit bieten fast alle Betriebssysteme spezielle Strukturen und Funktionen, um mit dem Hardwarespeicher zu interagieren. Zwei gängige Konzepte in den vom Betriebssystem bereitgestellten Speicherstrukturen sind Stack und Heap.

Ein Stack ist ein Speicherbereich, der für jedes laufende Programm im System reserviert ist und auf LIFO-Weise arbeitet. Wenn das Programm mit der Ausführung der Funktion main beginnt, erhält diese nämlich ihren Stack-Frame (eine Untermenge des Stack-Speichers), in dem lokale Variablen und Rückgabeadressen für Funktionsaufrufe automatisch gespeichert werden. Sobald der main eine andere Funktion aufruft, wird nach dem vorherigen fortlaufend ein neuer Stack-Frame erstellt. Der neueste Stack-Frame speichert die lokalen Objekte für die entsprechende Funktion und wenn er zurückkehrt, wird dieser Speicher frei.

Beachten Sie, dass die Stapelgröße auf den meisten Systemen standardmäßig festgelegt ist, aber bis zu einem gewissen Grad angepasst werden kann, wenn der Benutzer spezielle Anforderungen hat. Die Größenbeschränkung des Stapelspeichers macht ihn für kleine und meist temporäre Objekte geeignet. Beispielsweise beträgt die Standard-Stackgröße für das Benutzerprogramm im Linux-Betriebssystem 8 MB. Es kann kleiner sein als ein einzelnes JPEG-Foto, das ein Programm möglicherweise verarbeiten muss, daher muss der Benutzer diesen Platz mit größter Sorgfalt verwenden. Die im folgenden Codeausschnitt deklarierten Variablen werden alle im Stapelspeicher gespeichert. Generell wird jede lokale Variable auf dem Stack allokiert, wenn sie keine speziellen Spezifizierer wie static oder volatile hat.

#include <iostream>

using std::cout;
using std::endl;

int main() {
  int var1;
  int var2 = 123;
  int arr1[4] = {1, 2, 3, 4};
  int var3 = var2;

  cout << var1 << endl;
  cout << var2 << endl;
  cout << var3 << endl;

  return EXIT_SUCCESS;
}

Ausgabe:

0
123
123

Auf der anderen Seite gibt es einen Speicherbereich namens Heap (auch free store genannt), in dem grosse Objekte abgelegt und während der Laufzeit vom Programmierer manuell belegt werden können. Diese beiden Merkmale machen den Heap-Speicher dynamisch, da seine Größe nicht zur Kompilierzeit oder zu irgendeinem Zeitpunkt während der Programmausführung bestimmt werden muss. Das Programm kann Sonderfunktionen aufrufen und die Zuweisungen vom Betriebssystem anfordern. Beachten Sie, dass der Heap-Speicher aus der Sicht des Programms unendlich erscheinen kann, da er nicht darauf beschränkt ist, eine andere Zuweisungsfunktion aufzurufen, um mehr Speicher anzufordern. Allerdings verwaltet das Betriebssystem den Speicher für alle laufenden Prozesse; und es kann neue Zuweisungen ablehnen, wenn kein physischer Speicher mehr verfügbar ist.

Das Speichersystem im Betriebssystem ist ziemlich komplex und erfordert das Verständnis verschiedener betriebssystem-/hardwarespezifischer Konzepte, daher behandeln wir in diesem Thema nur mehr als das Nötigste über Heap- und Stack-Speicher. Die manuelle Verwaltung des Heap-Speichers in der Sprache C++ kann mit den Operatoren new/delete oder malloc/free erfolgen. Beachten Sie, dass diese Funktionen auf ähnliche Weise funktionieren, wobei der Benutzer normalerweise die Anzahl der zuzuweisenden Bytes angibt und die Adresse zurückgibt, an der die gleiche Speichermenge zugewiesen wurde. Der Programmierer kann folglich den gegebenen Speicherbereich nach Bedarf bearbeiten.

Das nächste Codebeispiel veranschaulicht mehrere Fälle des Zuordnens der verschiedenen Objekte im Heap-Speicher. Eine wichtige Funktion der manuellen Speicherverwaltung besteht darin, den zugewiesenen Speicherbereich an das Betriebssystem zurückzugeben, wenn er nicht mehr benötigt wird. Die letztgenannte Operation wird mit Hilfe von delete/free-Aufrufen ausgeführt, die ihren Gegenstücken für die Zuordnung entsprechen. Wenn das Programm den nicht benötigten Speicher nicht freigibt, besteht die Gefahr, dass dem Betriebssystem der Speicher ausgeht und das Programm dadurch möglicherweise beendet wird. Beachten Sie jedoch, dass das vorherige Problem hauptsächlich bei Programmen mit langer Laufzeit auftritt, und sie werden als Fehler durch Speicherlecks bezeichnet.

#include <iostream>

using std::cout;
using std::endl;

int main() {
  auto var4 = new int;
  cout << var4 << endl;

  int *arr2 = new int[4];
  auto arr3 = new int[4];
  cout << arr2 << endl;
  cout << arr3 << endl;

  delete var4;
  delete[] arr2;
  delete[] arr3;
  return EXIT_SUCCESS;
}
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Verwandter Artikel - C++ Memory