Что делает ulimit -s unlimited?

Понятно, что есть много связанных вопросов о распределении стека

Что и где находятся стек и куча?

Почему существует ограничение на размер стека?

Размер стека и кучи памяти

Однако на различных машинах * nix я могу выполнить команду bash

ulimit -s unlimited

или команда csh

set stacksize unlimited

Как это меняет способ выполнения программ? Есть ли какое-либо влияние на производительность программы или системы (например, почему бы не использовать это значение по умолчанию)?

В случае, если важны более подробные сведения о системе, меня больше интересуют программы, скомпилированные с помощью GCC в Linux, работающие на оборудовании x86_64.


person Brian Hawkins    schedule 23.01.2013    source источник


Ответы (3)


Когда вы вызываете функцию, в стеке выделяется новое «пространство имен». Вот так у функций могут быть локальные переменные. Поскольку функции вызывают функции, которые, в свою очередь, вызывают функции, мы продолжаем выделять все больше и больше места в стеке для поддержания этой глубокой иерархии пространств имен.

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

int eat_stack_space(void) { return eat_stack_space(); }
// If we compile this with no optimization and run it, our computer could crash.

Обычно использование тонны пространства стека является случайным или признаком очень глубокой рекурсии, которая, вероятно, не должна так сильно полагаться на стек. Таким образом, предел стека.

Влияние на производительность незначительно, но все же существует. Используя команду time, я обнаружил, что устранение ограничения стека увеличивает производительность на несколько долей секунды (по крайней мере, на 64-битной Ubuntu).

person Alex V    schedule 23.01.2013
comment
когда gcc-4.7 -O3 ваш smash_the_stack пример хвостовой рекурсии преобразуется в бесконечный цикл без каких-либо вызовов. - person Basile Starynkevitch; 23.01.2013
comment
@BasileStarynkevitch Компиляторы сейчас такие умные. Я изменил пример, чтобы gcc было сложнее оптимизировать, извините за это! - person Alex V; 24.01.2013
comment
Даже улучшенный пример с printf перед рекурсивным вызовом компилируется в цикл с gcc-4.7 -O3 - person Basile Starynkevitch; 24.01.2013
comment
@BasileStarynkevitch Черт. Я думаю, что суть сформулирована довольно ясно. Если вы хотите, чтобы gcc не оптимизировал разбиение стека для истечения срока обучения, просто скомпилировал его с gcc -O0. - person Alex V; 24.01.2013
comment
Нет, хороший способ - избежать хвостовой рекурсии. Поместите полезный код до и после рекурсивного вызова. - person Basile Starynkevitch; 24.01.2013
comment
@BasileStarynkevitch Я тестировал этот код 4.4 (у меня нет 4.7 в этой системе), и он не компилируется в цикл. - person Alex V; 25.01.2013
comment
@Maxwell Две ошибки: ограничение размера стека не имеет ничего общего с предотвращением сбоя всей системы. RAM - это RAM, это задача ядра - решить, как отобразить ее для стека или кучи. Создание стека 100 ГБ не более вредно, чем выделение 100 ГБ в куче: операции либо завершатся с ошибкой (сбой sbrk или exec), либо произойдет переопределение, и процессы будут убиты, когда вы используете память, пока система не выполнит ее снова обязательства памяти. В любом случае целостность всей системы безопасна. Процесс ничего не может сделать, чтобы победить ядро. - person Nicholas Wilson; 01.07.2013
comment
@Maxwell Во-вторых, превышение размера стека - это совершенно другая проблема по сравнению с разбиванием стека. Когда происходит переполнение стека, ядро ​​убивает процесс и все. В стек не записывается ничего, чего быть не должно, и никакого вреда (кроме завершения процесса) не возникает. - person Nicholas Wilson; 01.07.2013
comment
Это совершенно неверный ответ. У каждого процесса в Linux есть свой стек - нет такого понятия, как пространство системного стека. Стек растет вниз на x86, и переполнение происходит, когда верх стека (физически нижняя часть памяти стека) достигает предварительно установленного предела или встречает другое отображение памяти. Переполнение буфера стека происходит в обратном направлении. Было бы сложно перезаписать адрес возврата, если бы стек вместо этого вырастал вверх. - person Hristo Iliev; 11.05.2016

размер стека действительно может быть неограниченным. _STK_LIM - это значение по умолчанию, _STK_LIM_MAX - это что-то, что различается в зависимости от архитектуры, как видно из include/asm-generic/resource.h:

/*
 * RLIMIT_STACK default maximum - some architectures override it:
 */
#ifndef _STK_LIM_MAX
# define _STK_LIM_MAX           RLIM_INFINITY
#endif

Как видно из этого примера, общее значение бесконечно, где RLIM_INFINITY, опять же, в общем случае определяется как:

/*
 * SuS says limits have to be unsigned.
 * Which makes a ton more sense anyway.
 *
 * Some architectures override this (for compatibility reasons):
 */
#ifndef RLIM_INFINITY
# define RLIM_INFINITY          (~0UL)
#endif

Итак, я предполагаю, что реальный ответ таков: размер стека МОЖЕТ быть ограничен какой-то архитектурой, тогда неограниченная трассировка стека будет означать все, что определено для _STK_LIM_MAX, а в случае бесконечности - бесконечность. Для получения подробной информации о том, что означает установить его на бесконечность и какие последствия это может иметь, обратитесь к другому ответу, он намного лучше, чем мой.

person favoretti    schedule 23.01.2013
comment
Это не похоже на правду. В моей системе значение linux / resource.h составляет 10 * 1024 * 1024. Это также значение, выводимое командой ulimit -s. Я скомпилировал тестовую программу со статическим массивом 20 МБ, и она перестала работать. Однако, если я введу команду ulimit -s unlimited, она не выйдет из строя. - person Brian Hawkins; 23.01.2013
comment
Хм, это интересно. У меня создалось впечатление, что этот предел не выйдет. - person favoretti; 23.01.2013
comment
@BrianHawkins: mea culpa, провел еще несколько исследований, скорректировал ответ. Если эта информация не имеет значения, я могу полностью удалить ответ. - person favoretti; 23.01.2013

ulimit -s unlimited позволяет стеку расти неограниченно.

Это может предотвратить сбой вашей программы, если вы пишете программы рекурсивно, особенно если ваши программы не являются хвостовыми рекурсивными (компиляторы могут их «оптимизировать»), а глубина рекурсии велика.

person Abhishek Anand    schedule 14.02.2017
comment
Почему бы не сделать неограниченным размер стека по умолчанию? Мой вариант использования не включает рекурсию, а скорее старые программы на Фортране с большими статическими массивами, которые превышают значения по умолчанию в большинстве систем. - person Brian Hawkins; 16.02.2017
comment
потому что программа с ошибками может привести к сбою вашей системы. Эту опцию следует использовать только в том случае, если вы уверены, что программа не съедает всю доступную память. - person Jean-François Fabre; 19.06.2020
comment
Программа с ошибками также может продолжать выделять память из кучи (malloc) и приводить к сбою / зависанию системы. Системы обычно не устанавливают ограничения на размер кучи. - person Abhishek Anand; 25.06.2020