Можно ли определить, сколько места доступно в стеке?

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

Есть ли способ узнать, как далеко я могу нажать стек на данной платформе? Я смотрю в основном на мобильные устройства, но проблема может возникнуть на любой платформе.

Ответ 1

В * nix используйте getrlimit:

   RLIMIT_STACK
          The maximum size of the process stack, in bytes.  Upon
          reaching this limit, a SIGSEGV signal is generated.  To handle
          this signal, a process must employ an alternate signal stack
          (sigaltstack(2)).

В Windows используйте VirtualQuery:

Для первого вызова передайте ему адрес любого значения в стеке получить базовый адрес и размер в байтах зарезервированного пространства стека. На машине x86, где стек растет вниз, вычтите размер от базового адреса и VirtualQuery: это даст вам размер пространства, зарезервированного для стека (при условии, что вы не точно на пределе размера стека в то время). Суммируя два естественно, дает вам общий размер стека.

Нет никакого независимого от платформы метода, так как размер стека остается логически для реализации и хост-системы - на встроенном мини-SOC меньше ресурсов для распространения, чем на 128-ГБ RAM-сервере. Однако вы можете влиять на размер стека определенного потока на всех ОС, а также на вызовы, специфичные для API.

Ответ 2

Возможное переносное решение - написать распределитель самостоятельно.
Вам не нужно использовать стек процесса, просто имитируйте его в куче.
Выделите большой объем памяти в начале и напишите на нем распределитель стека, чтобы использовать его при распределении.
Google "Требования к подписчикам" для получения информации о том, как его достичь на С++.

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

Ответ 3

В стандартном С++ определенно нет. В переносном смысле, вероятно, нет. Иногда в конкретной ОС. Если ничего другого, вы можете открыть свой собственный исполняемый размер и проверить заголовки исполняемого файла, чтобы увидеть его стекирование. [Следующая проблема, конечно, "сколько стека использовалось до этого бита кода", что может быть трудно определить).

Если вы запускаете код в отдельном потоке, многие из (нисходящих) потоковых интерфейсов позволяют указать стек (или стекировать), например, Posix threads pthread_set_stacksize или MS _beginthread. Опять же, вы не знаете ТОЧНО, сколько места было использовано до того, как оно попадет в настоящий код потока, но это, вероятно, не огромная сумма.

Конечно, во встроенной системе (например, в мобильном телефоне) стекизация обычно довольно мала, 4K, 12K или 64KB очень обычна - иногда даже намного меньше, чем в некоторых системах.

Еще одна потенциальная проблема заключается в том, что вы не можете действительно знать, сколько пространства ACTUALLY используется в стеке - вы можете измерить после факта в скомпилированной системе и, конечно, если у вас есть локальный массив стека int array[25];, мы можем знать, что он занимает не менее 25 * sizeof(int) - но может быть заполнение, компилятор сохраняет регистры в стеке и т.д. и т.д.

Изменить, как запоздалая мысль: Я также не вижу большой пользы в наличии двух кодовых путей:

 if (enough_stack_space_for_something)
      use_stack_based_algorithm();
 else
      use_heap_based_algorithm();

Это добавит достаточное количество дополнительных накладных расходов, и больше кода, как правило, не является хорошим планом во встроенной/мобильной системе.

Edit2: Кроме того, если выделение памяти является основной частью среды выполнения, возможно, посмотрите, почему это так, например, создание блоков объектов?

Ответ 4

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

Стек представляет собой деталь реализации конкретной машины/ОС/компилятора. Следовательно, любой метод доступа к меткам стека будет специфичен для машинного/ОС/компилятора.

Пока вы не отвечаете на свой конкретный вопрос (Niels достаточно хорошо это рассмотрел), но как совет для вашей проблемной области: просто выделите большой кусок памяти в кучу. Нет никакой причины в стороне от удобства, что "реальный" стек любой другой. Очень рекурсивные (не хвостовые рекурсивные) алгоритмы часто требуют этого, чтобы гарантировать, что у них есть фактически неограниченный "стек". Языки скриптов, которые хотят, чтобы они отображали ошибку/исключение во время выполнения, а не сбой приложения-хоста, также часто делают это. Чтобы быть эффективными в отношении вещей, вы можете либо реализовать "разбитый стек" (например, std::deque предоставит вам), либо просто вы можете предварительно выделить стек, достаточно большой для ваших нужд.

Ответ 5

Нет стандартного способа сделать это из языка. Я даже не знаю документального расширения, которое может запросить.

Однако некоторые компиляторы имеют опции для установки размера стека. И платформа может указать, что она делает при запуске процесса, и/или предоставить способы установить размер стека нового потока, возможно, даже манипулировать существующим.

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