Как изменить размер стека, используя ulimit или на процесс в Mac OS X для программы на C или Ruby?

Кажется, что рекомендуемый способ установить размер стека для программы на C или Ruby (которая использует стек C), это с помощью ulimit в оболочке Bash. Но

$ ulimit -s
8192

$ ulimit -s 16384
-bash: ulimit: stack size: cannot modify limit: Operation not permitted

а также sudo тоже не помогает Есть ли способ установить его на 16 МБ, 32 МБ или 64 МБ? Я думал, что должен быть способ установить его для каждого вызова программы вместо установки общесистемного параметра?

Прямо сейчас 8192 вероятно, означает 8 МБ, что довольно мало, если сравнивать с тем, сколько процесс может использовать, иногда до 2 ГБ ОЗУ.

(обновленное примечание: ulimit -a может показать его текущие значения).

(обновление 2: на самом деле это выглядит как ulimit -s <value> для каждой оболочки, и что если вы установите его в первый раз, он обычно работает. Проблема в том, что если вы установите его во второй раз, то он может вернуть ошибку)

5 ответов

Решение

По-видимому, существует жесткое ограничение на размер стека для Mac OS X, взятое с http://lists.apple.com/archives/scitech/2004/Oct/msg00124.html оно довольно старое, и я не уверен, что его все еще верно, но для установки просто вызовите ulimit -s hard, его 65532. или около 65 мегабайт.

Я провел несколько тестов на снежном барсе, 10.6.8, и это похоже на правду.

$ ulimit -a
...
stack size              (kbytes, -s) 8192
...
$ ulimit -s 65533
-bash: ulimit: stack size: cannot modify limit: Operation not permitted
$ ulimit -s 65532
$

Я также нашел это http://linuxtoosx.blogspot.com/2010/10/stack-overflow-increasing-stack-limit.html хотя я не тестировал его, поэтому не могу особо сказать об этом.

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

вот краткое руководство:

#include <stdlib.h>

#define NUMBER_OF_BYTES 10000000 // about 10 megs
void test()
{
   char stack_data[NUMBER_OF_BYTES];          // allocating on the stack.
   char *heap_data = malloc(NUMBER_OF_BYTES); // pointer (heap_data) lives on the stack, the actual data lives on the heap.
}

int main()
{   
    test(); 
    // at this point stack_data[NUMBER_OF_BYTES] and *heap_data have being removed, but malloc(NUMBER_OF_BYTES) persists.
    // depending on the calling convention either main or test are responssible for resetting the stack.
    // on most compilers including gcc, the caller (main) is responssible.

    return 0;
}

$ ulimit -a
...
stack size              (kbytes, -s) 8192
...
$ gcc m.c
$ ./a.out
Segmentation fault
$ ulimit -s hard
$ ./a.out
$

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

Как только ulimit установлен, его можно только опускать, но не поднимать.

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

Как только ulimit установлен, его можно только опускать, но не поднимать.

Есть действительно мягкий (отображается с ulimit -s или же ulimit -Ss) и жесткий (отображается с ulimit -Hs) пределы. Но при установке лимита через ulimit -s повлияет на мягкие и жесткие значения.

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

Это будет работать:

# base values
$ ulimit -s
100
$ ulimit -Hs
100
$ ulimit -Ss
100
# lower soft limit only
$ ulimit -Ss 50
$ ulimit -s
50
$ ulimit -Hs
100
$ ulimit -Ss
50
# raise soft limit only
$ ulimit -Ss 100
$ ulimit -s
100
$ ulimit -Hs
100
$ ulimit -Ss
100
# lower soft and hard limit
$ ulimit -s 50
$ ulimit -s
50
$ ulimit -Hs
50
$ ulimit -Ss
50
# then impossible to raise soft limit due to hard limit
$ ulimit -s 100
-bash: ulimit: stack size: cannot modify limit: Operation not permitted
$ ulimit -Ss 100
-bash: ulimit: stack size: cannot modify limit: Invalid argument

Размер стека системы по умолчанию варьируется от версии ядра к ядру. Мой 10.7 - 16384, такой, что ulimit -s 16384 принимается моим Mac. Ты можешь попробовать sysctl kern.stack_size и он показывает размер стека только для чтения. мой 16384.
Вы можете увидеть эту техническую статью, http://developer.apple.com/library/mac/, чтобы узнать, как изменить размер стека по умолчанию для программы на Си. Для Ruby, поскольку это язык сценариев, вы должны увеличить размер его стека во время компоновки интерпретатора Ruby. За исключением очень глубоких вызовов функций или рекурсии или наличия очень большого массива и объектов, размещаемых в стеке, ваша программа не должна иметь большого стекового пространства. Вместо этого, используя кучу или динамическое распределение, вы можете использовать до 2 ГБ оперативной памяти по вашему желанию.

Я обнаружил, что с помощью /bin/zsh вместо /bin/sh сделал эту ошибку уйти.

Для меня ошибка произошла в сценарии оболочки, который называется ulimit -s unlimited, Когда сценарий был интерпретирован /bin/sh (т.е. имел #!/bin/sh как первая строка файла сценария), это вызвало ошибку. Напротив, при изменении его использовать zshКазалось, все работает нормально. zsh был достаточно умен, чтобы интерпретировать unlimited как "дайте мне самый большой предел, который будет иметь операционная система", и все работало так, как вы этого хотите.

Все ограничения, которые встроены ulimitэлементы управления фактически реализованы в ядре ОС, и поэтому вы должны видеть документацию по интерфейсу C для всей системы. Вот документация Apple для setrlimit(): https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setrlimit.2.html

(Обратите внимание, что путь к этому документу, похоже, указывает на iPhoneOS, но в содержимом по-прежнему говорится о «Mac OS X». Если у вас есть соответствующая документация, установленная локально, запустите man setrlimit в вашем терминале должна выпустить актуальную документацию.)

Вновь созданные процессы наследуют ограничения от fork() родительский или предыдущий процесс, который выполняет exec().

Другие вопросы по тегам