почему размер стековой памяти так ограничен?
============================================

 

 как куча. Стек должен храниться в постоянных ячейках памяти. Это означает, что вы не можете случайным образом распределить стек по мере необходимости, но вам нужно как минимум зарезервировать виртуальные адреса для этой цели. Чем больше размер зарезервированного виртуального адресного пространства, тем меньше потоков вы можете создать.

Например, 32-разрядное приложение обычно имеет виртуальное адресное пространство 2 ГБ. Это означает, что если размер стека составляет 2 МБ (по умолчанию в pthreads), то вы можете создать максимум 1024 потоков. Это может быть мало для приложений, таких как веб-серверы. Увеличение размера стека, скажем, до 100 МБ (т.е. вы резервируете 100 МБ, но не обязательно сразу выделяете 100 МБ для стека), ограничило бы количество потоков до 20, что может быть ограничено даже для простых приложений с графическим интерфейсом.

Интересный вопрос, почему у нас все еще есть этот предел на 64-битных платформах. Я не знаю ответа, но я предполагаю, что люди уже привыкли к некоторым «наилучшим методам стека»: будьте осторожны, выделяя огромные объекты в куче и, если необходимо, вручную увеличивайте размер стека. Поэтому никто не нашел полезным добавить «огромный» поддержка стека на 64-битных платформах.



**A limited stack size is an error detection and containment mechanism.**

Как правило, основная задача стека в C и C ++ состоит в том, чтобы отслеживать стек вызовов и локальные переменные, и если стек выходит за границы, это почти всегда является ошибкой в разработке и / или поведении приложения. ,

Если бы стеку было разрешено расти как угодно большим, эти ошибки (например, бесконечная рекурсия) будут обнаружены очень поздно, только после того, как ресурсы операционной системы будут исчерпаны. Это можно предотвратить, установив произвольное ограничение на размер стека. Фактический размер не так важен, за исключением того, что он достаточно мал, чтобы предотвратить деградацию системы.



 стек является непрерывным, поэтому, если вы выделяете 12 МБ, вы должны удалить 12 МБ, если хотите опуститься ниже того, что создали. Также перемещение объектов вокруг становится намного сложнее. Вот пример из реальной жизни, который может облегчить понимание:

Скажем, вы складываете коробки вокруг комнаты. Которым легче управлять:

stacking boxes of any weight on top of each other, but when you need to get something on the bottom you have to undo your entire pile. If you want to take a item out of the pile and give it to someone else you must take off all of the boxes and move the box to the other person's pile (Stack only)
You put all of your boxes (except for really small boxes) over in a special area where you do not stack stuff on top of other stuff and write down where you put it on a piece of paper (a pointer) and put the paper on the pile. If you need to give the box to someone else you just hand them the slip of paper from your pile, or just give them a photocopy of the paper and leave the original where it was in your pile. (Stack + heap)
Эти два примера являются грубыми обобщениями, и есть некоторые пункты, которые явно неверны в аналогии, но они достаточно близки, чтобы, надеюсь, помочь вам увидеть преимущества в обоих случаях.



 близко к ЦП (быстро), стек немного дальше (но все еще относительно близко), а куча - далеко (медленный доступ).

Стек живет в куче, но, тем не менее, поскольку он используется непрерывно, он, вероятно, никогда не покидает кэш-память ЦП, что делает его быстрее, чем просто средний доступ к куче.
Это является причиной сохранения размера стека; сохранить его в кеше как можно больше. Выделение больших стековых объектов (возможно, автоматическое изменение размера стека при переполнении) идет вразрез с этим принципом.

Так что это хорошая парадигма производительности, а не просто пережиток прошлого.



 вы можете получить больше - чаще всего, сказав компоновщику выделить дополнительное место в стеке.

Недостатком больших стеков является то, что если вы создаете много потоков, им потребуется по одному стеку каждый. Если все стеки выделяют несколько МБ, но не используют их, пространство будет потрачено впустую.

Вы должны найти правильный баланс для вашей программы.

Некоторые люди, такие как @BJovke, считают, что виртуальная память по существу свободна. Это правда, что вам не нужно, чтобы физическая память поддерживала всю виртуальную память. Вы должны быть в состоянии по крайней мере выдавать адреса виртуальной памяти.

Однако на типичном 32-разрядном ПК размер виртуальной памяти совпадает с размером физической памяти, поскольку у нас есть только 32 бита для любого адреса, виртуального или нет.

Поскольку все потоки в процессе используют одно и то же адресное пространство, они должны делить его между собой. И после того, как операционная система взяла на себя свою роль, «только» 2-3 ГБ осталось под заявку. И этот размер является пределом дляboth физическийand виртуальной памяти, потому что просто больше нет адресов.



 для которых вам нужен большой стек, могут быть выполнены другим способом.

Алгоритмы Седжвика "Алгоритмы" есть несколько хороших примеров "удаления" рекурсия из рекурсивных алгоритмов, таких как QuickSort, путем замены рекурсии итерацией. На самом деле алгоритм все еще рекурсивен, и все еще остается в виде стека, но вы выделяете стек сортировки в куче, а не используете стек времени выполнения.

(Я предпочитаю второе издание с алгоритмами, приведенными на Паскале. Его можно было использовать за восемь баксов.)

Другой способ взглянуть на это, если вы думаете, что вам нужен большой стек, ваш код неэффективен. Есть лучший способ, который использует меньше стека.



 что есть какая-то техническая причина, но это было бы странное приложение, которое просто создало в стеке только один огромный суперобъект. Стековые объекты испытывают недостаток в гибкости, что становится более проблематичным с увеличением размера - вы не можете вернуться, не уничтожив их, и вы не можете поставить их в очередь в другие потоки.