почему размер стековой памяти так ограничен?
когда вы выделяете память в куче, единственным ограничением является свободная оперативная память (или виртуальная память). Это делает Гб памяти.
Так почему же размер стека так ограничен (около 1 Мб) ? Какая техническая причина мешает вам создавать действительно большие объекты на стеке ?
обновление: мои намерения могут быть не ясны, я не хочется чтобы выделить огромные объекты в стеке и я не нужны большой стек. Этот вопрос просто чистый любопытство.
7 ответов:
моя интуиция заключается в следующем. Стек не так прост в управлении, как куча. Стек должен храниться в непрерывных ячейках памяти. Это означает, что вы не можете случайным образом распределить стек по мере необходимости, но вам нужно хотя бы зарезервировать виртуальные адреса для этой цели. Чем больше размер зарезервированного виртуального адресного пространства, тем меньше потоков можно создать.
например, 32-разрядное приложение обычно имеет виртуальное адресное пространство 2 ГБ. Это означает, что если размер стека составляет 2 МБ (по умолчанию в pthreads), то вы можете создать максимум 1024 потоков. Это может быть мало для таких приложений, как веб-серверы. Увеличение размера стека, скажем, до 100 МБ (т. е. вы резервируете 100 МБ, но не обязательно выделяете 100 МБ в стек сразу), ограничило бы количество потоков примерно до 20, что может быть ограничением даже для простых графических приложений.
интересный вопрос, почему у нас все еще есть этот предел на 64-битных платформах. Я не знаю ответ, но я предполагаю, что люди уже привыкли к некоторым "лучшим практикам стека": будьте осторожны, чтобы выделить огромные объекты в куче и, если необходимо, вручную увеличить размер стека. Поэтому никому не было полезно добавлять "огромную" поддержку стека на 64-битных платформах.
один аспект, который пока никто не упомянул:
ограниченный размер стека-это механизм обнаружения и локализации ошибок.
Если стеку будет разрешено расти сколь угодно большим, эти ошибки (например бесконечная рекурсия) будет поймана очень поздно, только после того, как ресурсы операционных систем будут исчерпаны. Это предотвращается путем установки произвольного ограничения на размер стека. Фактический размер не так важен, кроме того, что он достаточно мал, чтобы предотвратить деградацию системы.
Это просто размер по умолчанию. Если вам нужно больше, вы можете получить больше - чаще всего, сказав компоновщику выделить дополнительное пространство стека.
недостатком наличия больших стеков является то, что если вы создадите много потоков, им понадобится по одному стеку. Если все стеки выделяют несколько Мб, но не используют его, пространство будет потрачено впустую.
вы должны найти правильный баланс для вашей программы.
некоторые люди, как @BJovke, считают, что виртуальная память по сути, бесплатно. Это правда, что вам не нужно иметь физическую память, поддерживающую всю виртуальную память. Вы должны быть в состоянии, по крайней мере, выдавать адреса в виртуальную память.
однако на типичном 32-разрядном ПК размер виртуальной памяти совпадает с размером физической памяти - потому что у нас есть только 32 бита для любого адреса, виртуального или нет.
поскольку все потоки в процессе используют одно и то же адресное пространство, они должны разделить его между собой. И после того, как операционная система приняла участие,для приложения осталось" всего " 2-3 ГБ. И этот размер является пределом для и физическое и виртуальная память, потому что там просто нет больше адресов.
во-первых, стек непрерывен, поэтому, если вы выделяете 12 МБ, вы должны удалить 12 МБ, когда вы хотите пойти ниже того, что вы создали. Также перемещение объектов вокруг становится намного сложнее. Вот пример реального мира, который может сделать вещи легче понять:
скажем, вы укладываете коробки вокруг комнаты. Что проще в управлении:
- штабелировать коробки любого веса поверх Одина другого, но когда вам нужно получить что-то на дне вы должны отменить вся твоя куча. Если вы хотите взять предмет из кучи и отдать его кому-то другому, вы должны снять все коробки и переместить коробку в кучу другого человека (только стек)
- вы кладете все свои коробки (за исключением действительно маленьких коробок) в специальную область, где вы не складываете вещи поверх других вещей и записываете, где вы положили их на лист бумаги (указатель) и положили бумагу на кучу. Если вам нужно отдать коробку кому-то еще, вы просто передаете им слип или просто дайте им ксерокопию бумаги и оставьте оригинал там, где он был в вашей куче. (Стек + куча)
эти два примера являются грубыми обобщениями, и есть некоторые моменты, которые явно неверны в аналогии, но это достаточно близко, что, надеюсь, поможет вам увидеть преимущества в обоих случаях.
подумайте о стеке в порядке рядом с далеко. Регистры находятся близко к процессору (быстро), стек немного дальше (но все еще относительно близко), а куча находится далеко (медленный доступ).
стек живет в куче, но все же, поскольку он используется непрерывно, он, вероятно, никогда не покидает кэш(ы) ЦП, что делает его быстрее, чем просто средний доступ к куче. Это причина, чтобы сохранить стек разумного размера; чтобы сохранить его в кэше как можно больше. Выделение большого объекты стека (возможно, автоматическое изменение размера стека при переполнении) противоречит этому принципу.
Так что это хорошая парадигма для производительности, а не просто остатки от старых времен.
многие из вещей, которые вы думаете, вам нужен большой стек, может быть сделано другим способом.
в "алгоритмах" Седжвика есть несколько хороших примеров "удаления" рекурсии из рекурсивных алгоритмов, таких как QuickSort, путем замены рекурсии итерацией. На самом деле алгоритм все еще рекурсивен, и есть еще как стек, но вы выделяете стек сортировки в куче, а не используете стек времени выполнения.
(Я предпочитаю второе издание, с алгоритмами дано в Паскале. Его можно было использовать за восемь баксов.)
другой способ взглянуть на это, если вы думаете, что вам нужен большой стек, ваш код неэффективен. Есть лучший способ, который использует меньше стека.
Я не думаю, что есть какая-либо техническая причина, но это было бы странное приложение, которое только что создало только один огромный супер-объект в стеке. Объекты стека лишены гибкости, что становится более проблематичным с увеличением размера - вы не можете вернуться, не уничтожив их, и вы не можете поставить их в очередь к другим потокам.