Существует несколько различных методов, в зависимости от операционной системы (linux realtime vs. normal) и языковой системы времени исполнения:
1) динамический, обычно из-за ошибки страницы
предварительно выделить несколько реальных страниц по старшим адресам и назначить начальный sp для этого.Стек растет вниз, куча растет вверх.Если сбой страницы происходит несколько ниже дна стека, недостающие промежуточные страницы распределяются и отображаются.Эффективно увеличивая стопку сверху вниз автоматически.Обычно существует максимум, до которого выполняется такое автоматическое распределение, которое может или не может быть задано в среде (ulimit), exe-header или динамически настраиваться программой с помощью системного вызова (rlimit).Особенно эта настраиваемость сильно варьируется между различными ОС.Также обычно существует предел того, «насколько далеко» от дна стека ошибка страницы считается нормальной, и может произойти автоматический рост.Обратите внимание, что не все системы стекаются вниз: под HPUX он (используется?) Растет вверх, поэтому я не уверен, что делает Linux на PA-Risc (кто-то может это прокомментировать).
2)фиксированный размер
другие ОС (и особенно во встроенных и мобильных средах) либо имеют фиксированные размеры по определению, либо указываются в заголовке exe, либо указываются при создании программы / потока.Особенно во встроенных контроллерах реального времени, это часто является параметром конфигурации, и отдельные задачи управления получают фиксированные стеки (чтобы избежать ненужных потоков, занимающих память для задач управления с более высоким приоритетом).Конечно, и в этом случае память может быть выделена только виртуально, до тех пор, пока она действительно не понадобится.
3) По страницам, спагетти и аналогичные
такие механизмы, как правило, забыты, но все еще используютсяв некоторых системах времени выполнения (я знаю системы Lisp / Scheme и Smalltalk).Они распределяют и увеличивают стек динамически по мере необходимости.Однако не как отдельный сегмент, а как связная цепочка многостраничных блоков.Это требует, чтобы компилятор (и) генерировал другой код входа / выхода функции для обработки границ сегмента.Поэтому такие схемы, как правило, реализуются системой языковой поддержки, а не самой ОС (как раньше - вздох).Причина в том, что когда у вас много (скажем, тысяч) потоков в интерактивной среде, предварительное выделение, скажем, 1 МБ просто заполняет ваше виртуальное адресное пространство, и вы не можете поддерживать систему, в которой потребности в потоках отдельного потока ранее неизвестны (что являетсяобычно это происходит в динамической среде, где использование может ввести eval-код в отдельное рабочее пространство).Таким образом, динамическое распределение, как в схеме 1 выше, невозможно, потому что на пути будут другие потоки с их собственными стеками.Стек состоит из небольших сегментов (скажем, 8-64 КБ), которые выделяются и освобождаются из пула и связаны в цепочку сегментов стека.Такая схема может также потребоваться для высокопроизводительной поддержки таких вещей, как продолжения, сопрограммы и т. Д.
Современные Unix / Linux и (я думаю, но не на 100% уверенные) окна используют схему 1) для основного потокаваш exe и 2) для дополнительных (p-) потоков, которым требуется фиксированный размер стека, заданный создателем потока изначально.Большинство встроенных систем и контроллеров используют фиксированное (но настраиваемое) предварительное распределение (даже физически предварительно распределенное во многих случаях).
edit: typo