На практике это сложно (а иногда и невозможно) увеличить стек. Чтобы понять, почему требуется некоторое понимание виртуальной памяти.
В старые времена однопоточных приложений и непрерывной памяти три составляли три компонента адресного пространства процесса: код, куча и стек. То, как эти три были разбиты, зависело от ОС, но, как правило, сначала шел код, начиная с нижней части памяти, затем следовала куча, которая росла вверх, а стек начинался сверху памяти и рос вниз. Была также некоторая память, зарезервированная для операционной системы, но мы можем игнорировать это. Программы в те дни имели несколько более драматические переполнения стека: стек мог вылетать в кучу, и в зависимости от того, что обновлялось первым, вы либо работали с неверными данными, либо возвращались из подпрограммы в какую-то произвольную часть памяти.
Управление памятью несколько изменило эту модель: с точки зрения программы у вас все еще были три компонента карты памяти процесса, и они в целом были организованы одинаково, но теперь каждый из компонентов управлялся как независимый сегмент, и MMU будет сигнализировать ОС, если программа пыталась получить доступ к памяти вне сегмента. Когда у вас была виртуальная память, не было необходимости или желания предоставлять программе доступ ко всему ее адресному пространству. Таким образом, сегментам были назначены фиксированные границы.
Так почему же нежелательно предоставлять программе доступ ко всему ее адресному пространству? Потому что эта память представляет собой «поручить» против обмена; в любой момент может понадобиться перезаписать любую или всю память для одной программы, чтобы освободить место для памяти другой программы. Если каждая программа потенциально может потребовать 2 ГБ подкачки, то вам нужно будет предоставить достаточно подкачки для всех ваших программ или воспользоваться тем, что двум программам потребуется больше, чем они могут получить.
На этом этапе, при условии достаточного виртуального адресного пространства, вы можете расширить эти сегменты, если это необходимо, и сегмент данных (куча) действительно со временем увеличивается: вы начинаете с небольшого сегмента данных, и когда распределитель памяти запрашивает больше места, когда это нужно На этом этапе с помощью одного стека физически можно было бы расширить сегмент стека: ОС могла бы перехватить попытку вытолкнуть что-то за пределы сегмента и добавить больше памяти. Но это тоже не особо желательно.
Введите многопоточность. В этом случае каждый поток имеет независимый сегмент стека, опять же фиксированный размер. Но теперь сегменты располагаются один за другим в виртуальном адресном пространстве, поэтому невозможно расширить один сегмент, не перемещая другой - что вы не можете сделать, потому что программа потенциально может иметь указатели на память, находящуюся в стеке. Вы также можете оставить некоторое пространство между сегментами, но это пространство будет потрачено впустую почти во всех случаях. Лучшим подходом было возложить бремя на разработчика приложений: если вам действительно нужны глубокие стеки, вы можете указать это при создании потока.
Сегодня, с 64-битным виртуальным адресным пространством, мы можем создавать эффективно бесконечные стеки для практически бесконечного числа потоков. Но опять же, это не особенно желательно: почти во всех случаях переполнение стека указывает на ошибку в вашем коде. Предоставление вам стека в 1 ГБ просто откладывает обнаружение этой ошибки.