Можно ли определить, сколько места доступно в стеке?
Я архивирую небольшой программный движок, и я хотел бы дорого использовать стек для быстрых итераций больших наборов чисел. Но потом мне пришло в голову, что это может быть плохой идеей, поскольку стек не такой большой, как куча памяти. Но меня привлекает скорость стека и отсутствие методов кодирования динамического распределения.
Есть ли способ узнать, как далеко я могу нажать стек на данной платформе? Я смотрю в основном на мобильные устройства, но проблема может возникнуть на любой платформе.
Ответы
Ответ 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), а остальная - стек, приближающийся с другой стороны.