Установить размер стека для потоков, используя setrlimit
Я использую библиотеку, которая создает pthread, используя размер стека по умолчанию 8 МБ. Можно ли программно уменьшить размер стека потока, создаваемого библиотекой? Я пытался с помощью setrlimit(RLIMIT_STACK...)
внутри моего main()
функция, но это, кажется, не имеет никакого эффекта. ulimit -s
кажется, делает работу, но я не хочу устанавливать размер стека до выполнения моей программы.
Есть идеи, что я могу сделать? Спасибо
Обновление 1: похоже, я собираюсь отказаться от возможности устанавливать размер стека с помощью setrlimit(RLIMIT_STACK,...).
Я проверил резидентную память и обнаружил, что она намного меньше, чем виртуальная память. Это достаточно веская причина для меня отказаться от попыток ограничить размер стека.
2 ответа
Есть несколько аспектов ответа на этот вопрос.
Во-первых, как указано в комментариях, pthread_attr_setstacksize
это правильный способ сделать это. Если библиотека звонит pthread_create
Я не могу позволить вам сделать это, исправление библиотеки было бы идеальным решением. Если поток является чисто внутренним по отношению к библиотеке (не вызывая код из вызывающего приложения), он действительно должен установить собственное предпочтение размера стека на основе чего-то вроде PTHREAD_STACK_MIN + ITS_OWN_NEEDS
, Если он обращается к вашему коду, он должен позволить вам запросить, сколько стекового пространства вам нужно.
Во-вторых, в качестве детали реализации, glibc использует ограничение стека от setrlimit
/ulimit
получить размер стека для потоков, созданных pthread_create
, Возможно, вы можете повлиять на размер таким образом, но он не переносим и, как вы обнаружили, ненадежен даже там (он не работает, когда вы звоните setrlimit
изнутри самого процесса). Возможно, что glibc проверяет ограничение только один раз, когда соответствующий код инициализируется, поэтому я бы попытался переместить setrlimit
позвонить как можно раньше в main
чтобы увидеть, поможет ли это.
Наконец, размер стека для потоков может даже не относиться к вашему приложению. Даже если размер стека составляет 8 МБ, только страницы, которые были фактически изменены (вероятно, 4 КБ или не более 8 КБ, если у вас нет больших массивов в стеке), фактически используют физическую память. Остальное - просто связать виртуальное адресное пространство (из которых у вас всегда есть как минимум 2-3 ГБ) и, возможно, внести плату. По умолчанию Linux включает overcommit, поэтому плата за фиксацию не будет строго соблюдаться, и поэтому тот факт, что glibc запрашивает слишком много, может даже не иметь значения. Вы могли бы сделать проверку overcommit еще менее строгой, написав 1
в /proc/sys/vm/overcommit_memory
, но это приведет к потере информации о том, когда у вас "не хватает памяти", и вместо этого вызовет сбой вашей программы. В такой ограниченной системе вы можете предпочесть более строгий учет overcommit, но тогда вам нужно решить проблему с размером стека потоков...
Я думаю, что вам не повезло. Если используемая вами библиотека не предоставляет способ установки предела стека, вы не сможете изменить его после создания потока. Ограничения setrlimit и shell влияют на стек основного потока.
Потоки создаются в пространстве памяти процессов, поэтому их стеки выделяются при создании потоков. В Unix я считаю, что стек будет отображаться в ОЗУ по требованию, поэтому вы можете не использовать 8 Мегабайт ОЗУ, если вам это не нужно (виртуальная или резидентная память).