it-swarm.com.de

warum ist die Stapelspeichergröße so begrenzt?

Wenn Sie Speicherplatz auf dem Heapspeicher zuweisen, ist die einzige Beschränkung Free RAM (oder virtueller Speicher). Es macht GB Speicher. 

Warum ist die Stapelgröße also so gering (ca. 1 MB)? Welcher technische Grund hindert Sie daran, wirklich große Objekte auf dem Stapel zu erstellen?

Update : Meine Absicht ist möglicherweise nicht klar, ich möchte nicht, riesige Objekte auf dem Stapel zuzuordnen, und ich brauche nicht einen größeren Stapel. Diese Frage ist nur reine Neugier.

67
undu

Meine Intuition ist folgende. Der Stapel ist nicht so einfach zu verwalten wie der Heap. Der Stapel muss in fortlaufenden Speicherplätzen gespeichert werden. Das bedeutet, dass Sie den Stapel nicht nach Bedarf zufällig zuordnen können, aber Sie müssen mindestens virtuelle Adressen für diesen Zweck reservieren. Je größer der reservierte virtuelle Adressraum ist, desto weniger Threads können Sie erstellen.

Beispielsweise hat eine 32-Bit-Anwendung im Allgemeinen einen virtuellen Adressraum von 2 GB. Das bedeutet, wenn die Stack-Größe 2 MB beträgt (standardmäßig in pthreads), können Sie maximal 1024 Threads erstellen. Dies kann für Anwendungen wie Webserver klein sein. Das Erhöhen der Stapelgröße auf beispielsweise 100 MB (d. H. Sie reservieren 100 MB, müssen dem Stapel jedoch nicht sofort 100 MB zuweisen), würde die Anzahl der Threads auf etwa 20 begrenzen, was selbst für einfache GUI-Anwendungen eine Einschränkung darstellen kann.

Eine interessante Frage ist, warum haben wir diese Beschränkung auf 64-Bit-Plattformen noch immer. Ich kenne die Antwort nicht, aber ich gehe davon aus, dass die Leute bereits an einige "Best Practices" für Stacks gewöhnt sind: Achten Sie darauf, große Objekte auf dem Heap zuzuordnen, und erhöhen Sie bei Bedarf die Stackgröße manuell. Daher war es für niemanden sinnvoll, auf 64-Bit-Plattformen "riesige" Stack-Unterstützung hinzuzufügen.

39
user1202136

Ein Aspekt, den noch niemand erwähnt hat:

Eine begrenzte Stapelgröße ist ein Fehlererkennungs- und Eindämmungsmechanismus.

Im Allgemeinen besteht die Hauptaufgabe des Stacks in C und C++ darin, den Aufrufstack und die lokalen Variablen zu überwachen. Wenn der Stack außerhalb der Grenzen wächst, liegt dies fast immer im Design und/oder Verhalten der Anwendung .

Wenn der Stack beliebig groß werden darf, werden diese Fehler (wie unendliche Rekursion) erst sehr spät erkannt, nachdem die Ressourcen des Betriebssystems erschöpft sind. Dies wird verhindert, indem die Stapelgröße beliebig begrenzt wird. Die tatsächliche Größe ist nicht so wichtig, abgesehen davon, dass sie klein genug ist, um eine Systemverschlechterung zu verhindern.

19

Es ist nur eine Standardgröße. Wenn Sie mehr benötigen, können Sie mehr erreichen - meistens, indem Sie dem Linker sagen, dass er zusätzlichen Stackspeicherplatz zuweisen soll.

Der Nachteil bei großen Stapeln besteht darin, dass sie, wenn Sie viele Threads erstellen, jeweils einen Stack benötigen. Wenn alle Stapel mehrere MB zuweisen, diese aber nicht verwenden, wird der Speicherplatz verschwendet.

Sie müssen das richtige Gleichgewicht für Ihr Programm finden.


Einige Leute wie @BJovke glauben, dass virtueller Speicher im Wesentlichen frei ist. Es ist wahr, dass Sie keinen physischen Speicher benötigen, der den gesamten virtuellen Speicher unterstützt. Sie müssen mindestens Adressen an den virtuellen Speicher vergeben können.

Bei einem typischen 32-Bit-PC entspricht die Größe des virtuellen Speichers jedoch der Größe des physischen Speichers - da wir für jede Adresse nur 32 Bit haben, virtuell oder nicht. 

Da alle Threads in einem Prozess denselben Adressraum gemeinsam nutzen, müssen sie ihn zwischen ihnen aufteilen. Und nachdem das Betriebssystem seinen Teil übernommen hat, verbleiben "nur" 2-3 GB für eine Anwendung. Und diese Größe ist die Grenze für beide den physischen und den virtuellen Speicher, da es einfach keine Adressen mehr gibt.

13
Bo Persson

Zum einen ist der Stack kontinuierlich. Wenn Sie also 12 MB zuweisen, müssen Sie 12 MB entfernen, wenn Sie das, was Sie erstellt haben, nicht mehr benötigen. Auch das Bewegen von Objekten wird schwieriger. Hier ist ein reales Beispiel, das die Dinge leichter verständlich machen kann: 

Angenommen, Sie stapeln Kisten in einem Raum. Welches ist einfacher zu handhaben: 

  • stapeln von Boxen mit beliebigem Gewicht übereinander, aber wenn Sie etwas auf der Unterseite haben müssen, müssen Sie Ihren gesamten Stapel aufheben. Wenn Sie einen Gegenstand aus dem Stapel nehmen und an eine andere Person weitergeben möchten, müssen Sie alle Kisten abnehmen und die Kiste auf den Stapel der anderen Person stellen (nur Stapel).
  • Sie legen alle Ihre Kisten (außer wirklich kleine Kisten) in einen speziellen Bereich, in dem Sie keine Sachen auf andere Dinge stapeln, und notieren, wo Sie sie auf ein Blatt Papier (einen Zeiger) legen und das Papier auflegen der Stapel. Wenn Sie die Schachtel einer anderen Person übergeben müssen, geben Sie ihnen einfach den Zettel von Ihrem Stapel oder geben Sie ihnen nur eine Fotokopie des Papiers und lassen Sie das Original dort, wo es sich befindet. (Stapel + Haufen)

Diese zwei Beispiele sind grobe Verallgemeinerungen, und es gibt einige Punkte, die in der Analogie offensichtlich falsch sind, aber es ist nahe genug, dass es Ihnen hoffentlich dabei helfen wird, die Vorteile in beiden Fällen zu erkennen.

4

Viele der Dinge, für die Sie einen großen Stack benötigen, können auf andere Weise ausgeführt werden.

Sedgewicks "Algorithmen" bietet einige gute Beispiele für das "Entfernen" der Rekursion von rekursiven Algorithmen wie QuickSort, indem die Rekursion durch Iteration ersetzt wird. In der Realität ist der Algorithmus immer noch rekursiv und es gibt immer noch einen Stapel, aber Sie ordnen den Sortierstapel auf dem Heap zu, anstatt den Laufzeitstapel zu verwenden.

(Ich bevorzuge die zweite Ausgabe mit Algorithmen, die in Pascal angegeben sind. Sie kann für acht Dollar verwendet werden.)

Eine andere Sichtweise ist, wenn Sie der Meinung sind, dass Sie einen großen Stack benötigen, ist Ihr Code ineffizient. Es gibt einen besseren Weg, weniger Stapel zu verwenden.

0
Mike Crawford

Denken Sie an den Stapel in der Reihenfolge von nah bis weit. Die Register liegen nahe an der CPU (schnell), der Stack ist etwas weiter (aber immer noch relativ nah) und der Heap ist weit entfernt (langsamer Zugriff).

Der Stack lebt von dem Heap of Course, aber da er ständig verwendet wird, verlässt er wahrscheinlich niemals den/die CPU-Cache (s) und ist dadurch schneller als der durchschnittliche Heap-Zugriff. Dies ist ein Grund, den Stack vernünftig zu halten Größe um es so viel wie möglich im Cache zu halten. Das Zuordnen von großen Stapelobjekten (möglicherweise wird die Stapelgröße automatisch angepasst, wenn Überläufe auftreten) widerspricht diesem Prinzip.

Es ist also ein gutes Paradigma für die Leistung, nicht nur ein Überbleibsel aus alten Zeiten.

0
Ruud van Gaal