如何增加/proc/pid/cmdline的4096字节限制?

42

对于我的Java应用程序,它们的类路径非常长。当使用ps命令时,我无法看到指定的主类在参数列表的末尾。我认为这是由于Ubuntu系统在/proc/pid/cmdline上设置了大小限制所致。如何增加此限制?


作为一个非 Java 程序员,我想知道你是如何在 Windows 上运行它的。XP 有一个限制,我记得是 2048。 - Camilo Martin
8个回答

28

查看Java进程时,jps非常有用。

这将为您提供主类和JVM参数:

jps -vl | grep <pid>

1
对我来说更糟糕的是,它很快就被截断了。 - HaveAGuess
1
@HaveAGuess,wfm - 它显示主类,无论类路径有多长,这正是OP所要求的。(它还可以选择性地显示其他参数。) - Greg Price
对我也有效,显示了所有参数,适用于超长(超过4096个字符)的Weblogic命令行(Linux 64位)。谢谢Kevin! - t0r0X
我正在尝试使用“jps”命令查看Hadoop Java进程的完整类路径......但出于某种原因,“jps”甚至不会显示类路径! - ernesto
谢谢,这对我有用。我需要添加-m选项以查看命令行参数。 - Steve
jps -lvm 对我来说更好 - m 是必需的,用于显示传递给你的Java main 方法的命令行参数(而不是JVM参数)。 - javabrett

19

您无法动态更改此限制,该限制已经硬编码在内核中的fs/proc/base.c文件的PAGE_SIZE中:

 274        int res = 0;
 275        unsigned int len;
 276        struct mm_struct *mm = get_task_mm(task);
 277        if (!mm)
 278                goto out;
 279        if (!mm->arg_end)
 280                goto out_mm;    /* Shh! No looking before we're done */
 281
 282        len = mm->arg_end - mm->arg_start;
 283 
 284        if (len > PAGE_SIZE)
 285                len = PAGE_SIZE;
 286 
 287        res = access_process_vm(task, mm->arg_start, buffer, len, 0);

请注意,如果您愿意重新编译内核,这可以进行调整(请参见我的评论中的操作说明链接)。 - Jay
5
如果你愿意重新编译内核,任何东西都可以被调整,但仍然无法动态改变。 - Robert Gamble
16
重新编译内核就像搬到一个新房子,因为你不喜欢之前的沙发。 - Camilo Martin
2
这个问题在2015年6月已经得到解决(https://github.com/torvalds/linux/commit/c2c0bb44620dece7ec97e28167e32c343da22867),因此这个答案现在已经过时了。 - JdeBP

9
我目前绕过ps(或者更确切地说是/proc/PID/cmdline)4096字符命令行参数限制的方法是使用一个小脚本来替换java命令。
在开发过程中,我总是使用SUN的未打包JDK版本,无论是Linux还是Windows(例如下载bin而不是rpm.bin),而不使用操作系统安装的JRE或JDK。我不建议更改默认Java安装的脚本(例如,因为它可能破坏更新,被覆盖或创建问题等)。
所以假设java命令在/x/jdks/jdk1.6.0_16_x32/bin/java中,
首先将实际二进制文件移开:
mv /x/jdks/jdk1.6.0_16_x32/bin/java /x/jdks/jdk1.6.0_16_x32/bin/java.orig

然后创建一个脚本 /x/jdks/jdk1.6.0_16_x32/bin/java,例如:

    #!/bin/bash

    echo "$@" > /tmp/java.$$.cmdline
   /x/jdks/jdk1.6.0_16_x32/bin/java.orig $@

然后使脚本可运行。

chmod a+x /x/jdks/jdk1.6.0_16_x32/bin/java

如果复制上述内容,请确保在 /x/jdks/jdk1.6.0_16_x32/bin/java 中没有额外的空格,并且 #!/bin/bash 是第一行。

完整的命令行最终会出现在例如 /tmp/java.26835.cmdline 中,其中 26835 是 shell 脚本的 PID。我认为还有一些 shell 对命令行参数数量的限制,记不清了,但可能是 64K 字符。

您可以更改脚本以从 /tmp/java.PROCESS_ID.cmdline 中删除命令行文本,最后将脚本移动到类似于“java.script”的名称,并将实际二进制文件 java.orig 复制(cp -a)回到 java。当我达到 4K 限制时才使用脚本。

可能存在转义字符和路径中的空格等问题,但对我来说它运行良好。


这可能是最简单的方法。您还可以仅为该特定命令设置CLASSPATH环境变量,或在CLASSPATH和命令行之间拆分所需路径。 - We Are All Monica
很好的解决方法,可以查看完整的命令行,我也用它来编译javac。 - stivlo
如果您可以访问实际使用的Java可执行文件(例如在Eclipse中),则可以跳过二进制文件的移动,只需创建打印命令行(到文件)并启动Java应用程序的脚本。确保将脚本放置在JDK bin文件夹中。 - Barry NL

6
您可以使用jconsole访问原始命令行,而不受所有长度限制的影响。

1
可能会起作用并增加长度限制,但对于非常巨大的命令行,它不再起作用并被截断(我刚刚经历了这种情况)。 - stivlo

3

0

对于基于Java的程序,如果您只想检查主类收到的命令行参数,可以运行以下命令:

jps -m

-2

我相信如果你在/proc/$pid/cmdline中看到参数被截断,那么你实际上已经超出了操作系统支持的最大参数长度。据我所知,在Linux中,大小限制为内存页面大小。请参考"ps ww" length restriction

唯一的解决方法是重新编译内核。如果你有兴趣这样做来解决这个问题,那么你可能会发现这篇文章有用:"Argument list too long": Beyond Arguments and Limitations

其他参考资料:
ARG_MAX, maximum length of arguments for a new process


2
你评论的第一部分是不正确的。在我的系统上,getconf ARG_MAX 表示 ARG_MAX = 2097152(这意味着我的最大参数长度为2兆字节)。然而,/proc/$pid/cmdline 被截断到 PAGE_SIZE,即4096。你提供的链接并没有涵盖这种特定情况 - 我不知道改变 fs/proc/base.c 中相关位是否会引起其他问题。 - We Are All Monica

-3
也许你需要使用 ps 命令的 'w' 参数。如果想要更多输出,可以加两个 'w'。这会告诉 ps 忽略终端的行宽限制。

2
不行,即使加上 ww 选项,它也会在 4096 处截断。我认为 ps 命令是从 /prod/pid/cmdline 这个路径中读取信息的,而这个路径也是被截断的。 - user27635
只是为了澄清@Caskey所说的“添加两个以获得更大的输出”,那就是-w -w(或-ww)以在输出中获得无限宽度。 - Jay
很抱歉,Jay,似乎它不是无限的,而是限制在4096个字符以内。 - AJP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接