Проблема размера стека по умолчанию в NPTL
Я занимаюсь разработкой многопоточного модульного приложения с использованием языка программирования C и NPTL 2.6. Для каждого плагина создается поток POSIX. Проблема в том, что каждый поток имеет свою собственную область стека, так как размер стека по умолчанию зависит от выбора пользователя, в некоторых случаях это может привести к огромному потреблению памяти.
Чтобы предотвратить ненужное использование памяти, я использовал что-то подобное для изменения размера стека перед созданием каждого потока:
pthread_attr_t attr;
pthread_attr_init (&attr);
pthread_attr_getstacksize(&attr, &st1);
if(pthread_attr_setstacksize (&attr, MODULE_THREAD_SIZE) != 0) perror("Stack ERR");
pthread_attr_getstacksize(&attr, &st2);
printf("OLD:%d, NEW:%d - MIN: %d\n", st1, st2, PTHREAD_STACK_MIN);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/* "this" is static data structure that stores plugin related data */
pthread_create(&this->runner, &attr, (void *)(void *)this->run, NULL);
РЕДАКТИРОВАТЬ I: добавлен раздел pthread_create().
Это не сработало, как я ожидал, размер стека сообщил pthread_attr_getstacksize()
изменено, но общее использование памяти приложением (из вывода ps/top/pmap) не изменилось:
СТАРЫЙ:10485760, НОВЫЙ:65536 - МИНУТА: 16384
Когда я использую ulimit -s MY_STACK_SIZE_LIMIT
перед запуском приложения добиваюсь ожидаемого результата.
Мои вопросы:
1-) Есть ли какой-либо переносимый (между вариантами UNIX) способ изменить (по умолчанию) размер стека потока после запуска приложения (конечно, до создания потока)?
2-) Можно ли использовать одну и ту же область стека для каждого потока?
3-) Возможно ли полностью отключить стек для потоков без особой боли?
2 ответа
Ответы для № 2 и № 3 - нет и нет. Каждому потоку нужен стек (куда еще идут ваши локальные переменные и адреса возврата?), И они должны быть уникальными для каждого потока (в противном случае потоки перезаписывают локальные переменные и адреса возврата друг друга, что приводит к краху всех).
Что касается #1... вызов установленного размера стека является как раз ответом на это. Я предлагаю вам определить приемлемый размер для создания ваших тем и установить его.
Что касается того, почему вещи не выглядят правильно для вас в top
.... top
печально известный лжец об использовании памяти.:-) Неужели вещи не распределяются или не убиваются OOM? Не удалось создать поток? Производительность страдает и страничка на диск увеличивается? Если ответ на эти вопросы - нет, то я не думаю, что есть о чем беспокоиться.
Обновление на основе некоторых комментариев ниже и выше:
Во-первых, 16 КБ все еще достаточно велики для того, что, как вы говорите, не требует много места в стеке. Если вы действительно хотите стать маленьким, я бы хотел сказать 4096 или 8192 для x86 Linux. Во-вторых, да, вы можете установить указатель стека вашего процессора на что-то другое... Но когда вы malloc()
или же mmap()
Это займет место. Я не знаю, как вы думаете, это поможет установить указатель стека на что-то еще. Тем не менее, если вы действительно чувствуете, что поток, который вызывает main()
слишком большой стек (я бы сказал, что это немного сумасшедший) и что pthread_attr_setstacksize()
не позволяет вам стать достаточно маленьким (?), тогда, возможно, вы можете посмотреть на непереносимые вещи, такие как создание потоков, вызвав clone()
syscall и указание стеков на основе указателя стека основного потока, или буфера из другого места, или чего-то еще. Но вам все еще понадобится стек для каждого потока, и у меня есть чувство top
все еще собирается разочаровать вас. Может быть, ваши ожидания немного высоки.
Я тоже видел эту проблему. Непонятно, как учитываются стеки, но "лишнее" пространство засчитывается в общую виртуальную машину, и если вы столкнетесь с границей процесса, у вас возникнут проблемы (даже если вы не используете это пространство). Кажется, это зависит от того, какую версию Linux вы используете (даже в пределах семейства 2.6), и от того, 32-битная или 64-битная версия у вас.