Поскольку Linux-2.6.23 ARG_MAX
не обязательно предварительно определенная константа, общий размер аргументов разрешаются составлять до 1/4 от размера стека (см ulimit -s
размер стека в Кб, но /proc/1/limits
более определенны). Однако ARG_MAX
предназначен не только для аргументов процесса, он также содержит переменные среды, которые вам, возможно, придется учитывать.
POSIX определяет, что означает ARG_MAX
, и приемлемый нижний предел _POSIX_ARG_MAX
4096). Его статическое значение (исторически) доступно через #define
в системных заголовках, а также оно устанавливается в заголовочных файлах ядра Linux. Его эффективное значение доступно с помощью sysconf()
или getconf ARG_MAX
из командной строки.
Если вы проверите заголовки glibc (sys/param.h
), вы увидите это:
/* The kernel headers defines ARG_MAX. The value is wrong, though. */
#ifdef __undef_ARG_MAX
# undef ARG_MAX
# undef __undef_ARG_MAX
#endif
Это из glibc-2.17, это появилось около 2.11 (2009), первая поддержка для этих дат - 2.8 (2008), но до 2.14 (2011) была ошибка в вышеупомянутой логике, которая мешала ему работать должным образом. Цель состоит в том, чтобы убедиться, что ARG_MAX
не определен, если он не является константой, поэтому программы должны полагаться на sysconf()
. (Даже если он определен, это может быть только нижний гарантированный предел, и программы должны использовать sysconf()
для определения верхних пределов переменной, см. sysconf(3)
)
Вы можете проверить, что видит ваш компилятор C (только синтаксис gcc
, bash
/zsh
):
$ gcc -E -dM -x c <(echo "#include <sys/param.h>") | fgrep ARG
#define ARG_MAX 131072
#define NCARGS ARG_MAX
#define _POSIX_ARG_MAX 4096
Приведенный выше вывод получен из старой системы (2.6.27), в которой есть поддержка ядра, но не полная среда выполнения (поддержка glibc). Если вы не видите строки ARG_MAX
то это не предопределенный предел, и вы должны использовать (sysconf) getconf ARG_MAX
:
$ getconf ARG_MAX
2097152
Полезный способ проверить поддержку также:
$ xargs --show-limits < /dev/null
Your environment variables take up 2542 bytes
POSIX upper limit on argument length (this system): 2092562
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2090020
Size of command buffer we are actually using: 131072
Это из системы linux-2.6.37/glib-2.13 с более высокими лимитами. Обратите внимание на последнюю строку вывода, xargs
умолчанию (время сборки) до "разумного" предела, возможно, в случае, если какой-либо из процессов, которые он запускает, не способен обрабатывать очень большие значения. Вы можете изменить это во время выполнения с опцией -s
. Кроме того, если у вас действует ulimit -s
, эти цифры могут быть ниже. Это должно работать правильно, начиная с findutils-4.3.9 (2007). Смотрите также: http://www.gnu.org/software/coreutils/faq/coreutils-faq.html#Argument-list-too-long
Чтобы проверить Perl:
% perl -MPOSIX -e 'print ARG_MAX . "\n"';
131072
Выше опять из старой системы, новая система должна показать:
% perl -MPOSIX -e 'print ARG_MAX . "\n"';
Your vendor has not defined POSIX macro ARG_MAX, used at -e line 1
Подвести итоги:
- Если вы работаете с ядром, выпущенным после 2.6.23, ядро разрешит передавать большие размеры при создании процесса. Это необходимое, но не достаточное условие.
- Родительский процесс не должен применять какие-либо неверные ограничения времени выполнения (например, с жестко запрограммированным
ARG_MAX
), вместо этого он должен проверять коды ошибок exec()
E2BIG
и должен использовать sysconf(_SC_ARG_MAX)
при необходимости.
- Дочерний процесс не должен применять какие-либо неправильные ограничения времени выполнения, в частности его код запуска, который обрабатывает ядро, при условии, что параметры не должны иметь неправильных жестко заданных ограничений (например, при настройке
argc
, argc
, области среды для использования во время выполнения). Обычно это делается в libc (glibc).
- Для родителей и детей вам также может понадобиться настроить и собрать поддержку времени из libc (или эквивалентную). Для glibc для этого требуется как минимум glibc-2.8 (хотя должна быть возможность обойти его, он может быть не простым и не чистым)
Проблемной комбинацией является обновленное (linux> = 2.6.23) ядро, но отсутствует или подозревается поддержка glibc (glibc <= 2.14)
Если вы работаете с более старым ядром, сначала убедитесь, что ваш поставщик не перенес эту функцию обратно. В противном случае вы можете в принципе изменить ограничение ядра и перекомпилировать, но вам также может понадобиться изменить хотя бы некоторые системные заголовки или исходный код для рабочей поддержки.
Программы должны иметь возможность обрабатывать произвольные значения, но это не всегда так: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html
Приложения не должны принимать какое-либо конкретное значение для ограничения. [...] Однако следует отметить, что многие из перечисленных пределов не являются инвариантными, и во время выполнения значение предела может отличаться от значений, указанных в этом заголовке, по следующим причинам:
- Предел зависит от имени пути.
- Предел различается между компиляцией и машинами времени выполнения.
По этим причинам приложение может использовать функции fpathconf(), pathconf() и sysconf() для определения фактического значения лимита во время выполнения.