我必须将256Kb的文本作为参数传递给“aws sqs”命令,但是在命令行中运行的限制大约为140Kb。许多地方已经讨论过it been solved in the Linux kernel as of 2.6.23 kernel。
但无法让它发挥作用。我正在使用3.14.48-33.39.amzn1.x86_64
以下是一个简单的测试示例:
#!/bin/bash
SIZE=1000
while [ $SIZE -lt 300000 ]
do
echo "$SIZE"
VAR="`head -c $SIZE < /dev/zero | tr '\0' 'a'`"
./foo "$VAR"
let SIZE="( $SIZE * 20 ) / 19"
done
foo
脚本只是:
#!/bin/bash
echo -n "$1" | wc -c
我的输出是:
117037
123196
123196
129680
129680
136505
./testCL: line 11: ./foo: Argument list too long
143689
./testCL: line 11: ./foo: Argument list too long
151251
./testCL: line 11: ./foo: Argument list too long
159211
那么,如何修改testCL
脚本的问题是它可以传递256Kb的数据?顺便说一下,我已经尝试将ulimit -s 65536
添加到脚本中,但没有帮助。
如果这显然是不可能的,我可以处理这个问题,但是你可以从上面的链接中阐明这个引用
“虽然Linux不是Plan 9,但在2.6.23中,Linux正在添加变量 参数长度。从理论上讲,你不应经常打“论证 列表太长“错误再次,但这个补丁也限制了最大值 参数长度为最大堆栈限制的25%(ulimit -s)。“
答案 0 :(得分:3)
<强> 编辑: 强>
我终于能够将&lt; = 256KB作为单个命令行参数传递(参见底部的 edit(4))。但是,请仔细阅读我是如何做到的,并自行决定这是否是您想要的方式。至少你应该能够理解为什么你会被困'&#39;否则就是我发现的。
ARG_MAX
与ulim -s
/ 4的耦合引入了MAX_ARG_STRLEN
作为最大值。论证的长度:
/*
* linux/fs/exec.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
...
#ifdef CONFIG_MMU
/*
* The nascent bprm->mm is not visible until exec_mmap() but it can
* use a lot of memory, account these pages in current->mm temporary
* for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we
* change the counter back via acct_arg_size(0).
*/
...
static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
return len <= MAX_ARG_STRLEN;
}
...
#else
...
static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
return len <= bprm->p;
}
#endif /* CONFIG_MMU */
...
static int copy_strings(int argc, struct user_arg_ptr argv,
struct linux_binprm *bprm)
{
...
str = get_user_arg_ptr(argv, argc);
...
len = strnlen_user(str, MAX_ARG_STRLEN);
if (!len)
goto out;
ret = -E2BIG;
if (!valid_arg_len(bprm, len))
goto out;
...
}
...
MAX_ARG_STRLEN
定义为linux/include/uapi/linux/binfmts.h
中页面大小的32倍:
...
/*
* These are the maximum length and maximum number of strings passed to the
* execve() system call. MAX_ARG_STRLEN is essentially random but serves to
* prevent the kernel from being unduly impacted by misaddressed pointers.
* MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
*/
#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
#define MAX_ARG_STRINGS 0x7FFFFFFF
...
默认页面大小为4KB,因此您无法传递超过128KB的参数。
我现在无法尝试,但如果可能,请切换到巨大的页面模式(页面大小4MB)解决此问题。
有关详细信息和参考资料,请参阅this answer至a similar question on Unix & Linux SE。
<强> 编辑: 强>
<强> (1) 强>
根据{{3}},可以通过在内核配置中启用x86_64
并将CONFIG_TRANSPARENT_HUGEPAGE
设置为CONFIG_TRANSPARENT_HUGEPAGE_MADVISE
来将n
Linux的页面大小更改为1MB。
<强> (2) 强>
使用上面的配置重新编译我的内核后,getconf PAGESIZE
仍会返回4096。
根据{{3}} CONFIG_HUGETLB_PAGE
,我还需要通过CONFIG_HUGETLBFS
提取。我现在正在重新编译并将再次测试。
<强> (3) 强>
我在启用CONFIG_HUGETLBFS
的情况下重新编译了我的内核,现在/proc/meminfo
包含this answer中提到的相应HugePages_*
条目。
但是,根据getconf PAGESIZE
的页面大小仍未更改。因此,虽然我现在应该可以通过mmap
调用请求大页面,但确定MAX_ARG_STRLEN
的内核默认页面大小仍然固定为4KB。
<强> (4) 强>
我将linux/include/uapi/linux/binfmts.h
修改为#define MAX_ARG_STRLEN (PAGE_SIZE * 64)
,重新编译了我的内核,现在您的代码生成:
...
117037
123196
123196
129680
129680
136505
143689
151251
159211
...
227982
227982
239981
239981
252611
252611
265906
./testCL: line 11: ./foo: Argument list too long
279901
./testCL: line 11: ./foo: Argument list too long
294632
./testCL: line 11: ./foo: Argument list too long
所以现在限制从128KB移动到256KB。 我不知道潜在的副作用。 据我所知,我的系统似乎运行得很好。
答案 1 :(得分:2)
只需将参数放入某个文件中,然后修改程序即可接受&#34;参数&#34;从文件。一个常见的约定(特别是GCC和其他几个GNU程序使用)是像remembering last dir
这样的参数要求你的程序从文件@/tmp/arglist.txt
读取参数,通常每个参数一行
您可能通过长环境变量传递一些数据,但它们也是有限的(内核的限制实际上是/tmp/arglist.txt
的大小初始堆栈,包含程序参数和环境)
或者,修改您的程序以通过某个配置文件进行配置,该文件包含您希望通过参数传递的信息。
(如果你可以重新编译你的内核,你可能会尝试增加 - 比你的可用内存小得多的两个更大的功率,例如2097152- main
ARG_MAX
重新编译内核之前在#define
中使用-d
在其他方面,没有办法规避这种限制(参见execve(2)手册页及其参数和环境大小的限制部分) - 一旦提高了堆栈限制(将setrlimit(2)与linux-4.*/include/uapi/linux/limits.h
一起使用,通常在父shell中内置RLIMIT_STACK
。否则你需要处理它。