In der Praxis ist es schwierig (und manchmal unmöglich), den Stapel zu vergrößern. Um zu verstehen, warum dies erforderlich ist, müssen Sie den virtuellen Speicher verstehen.
In Ye Olde Days mit Single-Thread-Anwendungen und zusammenhängendem Speicher waren drei Komponenten eines Prozessadressraums: der Code, der Heap und der Stapel. Wie diese drei angeordnet waren, hing vom Betriebssystem ab, aber im Allgemeinen stand der Code an erster Stelle, beginnend am unteren Ende des Speichers, der Heap kam als nächstes und wuchs nach oben, und der Stack begann am oberen Ende des Speichers und wuchs nach unten. Es war auch etwas Speicher für das Betriebssystem reserviert, aber das können wir ignorieren. Programme hatten damals etwas dramatischere Stapelüberläufe: Der Stapel stürzte in den Heap, und je nachdem, was zuerst aktualisiert wurde, würden Sie entweder mit schlechten Daten arbeiten oder von einer Subroutine in einen beliebigen Teil des Speichers zurückkehren.
Die Speicherverwaltung hat dieses Modell ein wenig verändert: Aus Sicht des Programms hatten Sie noch die drei Komponenten einer Prozessspeicherzuordnung und sie waren im Allgemeinen auf die gleiche Weise organisiert, aber jetzt wurde jede der Komponenten als unabhängiges Segment verwaltet, und die MMU signalisierte dies Betriebssystem, wenn das Programm versucht hat, auf Speicher außerhalb eines Segments zuzugreifen. Sobald Sie über virtuellen Speicher verfügten, bestand keine Notwendigkeit oder kein Wunsch mehr, einem Programm Zugriff auf den gesamten Adressraum zu gewähren. So wurden den Segmenten feste Grenzen zugewiesen.
Warum ist es also nicht wünschenswert, einem Programm Zugriff auf seinen gesamten Adressraum zu gewähren? Weil diese Erinnerung eine "Festschreibegebühr" gegen den Swap darstellt; Zu jedem Zeitpunkt muss möglicherweise der gesamte oder ein Teil des Speichers für ein Programm geschrieben werden, um Platz für den Speicher eines anderen Programms zu schaffen. Wenn jedes Programm möglicherweise 2 GB Swap verbrauchen könnte, müssten Sie entweder genug Swap für alle Ihre Programme bereitstellen oder die Chance nutzen, dass zwei Programme mehr benötigen, als sie bekommen könnten.
Unter der Annahme eines ausreichenden virtuellen Adressraums könnten Sie diese Segmente bei Bedarf erweitern, und das Datensegment (Heap) wächst tatsächlich mit der Zeit: Sie beginnen mit einem kleinen Datensegment, und wenn der Speicherzuordner wann mehr Speicherplatz anfordert es ist nötig. Zu diesem Zeitpunkt wäre es mit einem einzelnen Stapel physikalisch möglich gewesen, das Stapelsegment zu erweitern: Das Betriebssystem könnte den Versuch abfangen, etwas außerhalb des Segments zu verschieben und mehr Speicher hinzuzufügen. Dies ist aber auch nicht besonders wünschenswert.
Geben Sie Multithreading ein. In diesem Fall hat jeder Thread ein unabhängiges Stapelsegment, wiederum mit fester Größe. Aber jetzt werden die Segmente nacheinander im virtuellen Adressraum angeordnet, sodass es keine Möglichkeit gibt, ein Segment zu erweitern, ohne ein anderes zu verschieben. Dies ist nicht möglich, da das Programm möglicherweise Zeiger auf den im Stapel befindlichen Speicher enthält. Sie könnten alternativ etwas Platz zwischen den Segmenten lassen, aber dieser Platz würde in fast allen Fällen verschwendet. Ein besserer Ansatz bestand darin, den Anwendungsentwickler zu entlasten: Wenn Sie wirklich tiefe Stapel benötigen, können Sie dies beim Erstellen des Threads angeben.
Mit einem virtuellen 64-Bit-Adressraum könnten wir heute praktisch unendlich viele Stapel für praktisch unendlich viele Threads erstellen. Aber auch das ist nicht besonders wünschenswert: In fast allen Fällen weist ein Stapelüberlauf auf einen Fehler in Ihrem Code hin. Wenn Sie einen 1-GB-Stack bereitstellen, wird die Entdeckung dieses Fehlers lediglich verzögert.