Подтвердить что ты не робот

Почему размер памяти стека настолько ограничен?

Когда вы выделяете память в кучу, единственным ограничением является свободное ОЗУ (или виртуальная память). Это делает Gb памяти.

Итак, почему размер стека настолько ограничен (около 1 Мб)? Какая техническая причина мешает вам создавать действительно большие объекты в стеке?

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Один аспект, о котором никто еще не упомянул:

Ограниченный размер стека - это механизм обнаружения и ограничения ошибок.

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

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

Ответ 3

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

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

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


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

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

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

Ответ 4

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

Скажите, что вы укладываете ящики вокруг комнаты. Что проще в управлении:

  • укладки коробок любого веса друг на друга, но когда вам нужно что-то получить, вы должны отменить всю свою кучу. Если вы хотите вытащить предмет из кучи и передать его кому-то другому, вы должны снять все коробки и перенести коробку в другую кучу человека (только для стека).
  • Вы помещаете все свои коробки (за исключением действительно маленьких коробок) в специальную область, где вы не складываете вещи поверх других вещей и записываете туда, где вы кладете ее на лист бумаги (указатель) и помещаете бумага на куче. Если вам нужно предоставить коробку кому-то другому, вы просто передадите им бумажку из своей кучи или просто дайте им фотокопию бумаги и оставите оригинал там, где он был в вашей куче. (Stack + heap)

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

Ответ 5

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

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

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

Ответ 6

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

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

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

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

Ответ 7

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