尝试使用Java 1.7.0_21和_25在Mac OS X 10.8.4上运行的Java Web Start应用程序中使用ProcessBuilder执行特定命令时遇到了问题。
我使用ProcessBuilder执行“/ usr / sbin / system_profiler”命令以获取有关客户端计算机的一些信息(例如cpu名称,#processor等)。
启动Web时正确执行命令:
启动应用程序通过以下方式启动时,命令不正确执行:
在使用Web Start快捷方式启动的情况下,“system_profiler”进程会创建一个子系统“system_profiler”,它会创建自己的子级,依此类推,直到 最终我收到以下错误(可能是在进程可用性耗尽时):
Failed to gather report from '/usr/sbin/system_profiler -xml SPHardwareDataType -detailLevel full', exception: couldn't fork: errno 35
注意:即使“/ usr / sbin / system_profiler”仅使用“SPHardwareDataType”参数启动,也会出现上述错误。
Activity Monitor showing created processes
这个问题似乎特定于“system_profiler”命令,因为它不会发生在其他命令的(通常很小的)随机采样中。
我还尝试了几种不同的方法来执行命令:
/usr/sbin/system_profiler
/usr/sbin/system_profiler SPHardwareDataType
/bin/sh -c /usr/sbin/system_profiler
/bin/sh -c /usr/sbin/system_profiler SPHardwareDataType
/bin/tcsh -c /usr/sbin/system_profiler
所有组合都有相同的行为。
应用程序包Info.plist在“WebStartArgs”键下包含以下键值对:
- Item 0: -localfile
- Item 1: -online
- Item 2: -J-Djnlp.application.href=http://localhost:8080/test/test.jnlp
- Item 3: /Users/blah/Library/Application Support/Oracle/Java/Deployment/cache/6.0/40/744be8-7ce41b1a
如上所述,我尝试使用相同的参数通过命令行启动,但问题不会发生。
这是一个展示问题的精简测试应用程序:
import java.io.*;
import java.util.Arrays;
public class TestProcessBuilder {
public static void main(String[] commands) throws IOException, InterruptedException {
System.out.println("Args: " + Arrays.toString(commands));
final ProcessBuilder pb = new ProcessBuilder(commands).redirectErrorStream(true);
System.out.println("Environment: " + pb.environment());
final Process p = pb.start();
final StringBuilder buffer = new StringBuilder();
Thread t = new Thread() {
@Override
public void run() {
InputStream stdoutStream = null;
try {
stdoutStream = new BufferedInputStream(p.getInputStream());
for(;;) {
int c = stdoutStream.read();
if(c == -1)
break;
buffer.append((char) c);
}
System.out.println("stdout buffer: " + buffer);
} catch(IOException e) {
throw new RuntimeException(e);
} finally {
close(stdoutStream);
}
}
};
t.start();
int result = p.waitFor();
t.join();
if(result != 0) {
throw new RuntimeException("Error result: " + result + " - " + buffer);
}
}
private static void close(Closeable closeable) {
try {
if(closeable != null)
closeable.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
作为一个注释,我也试过没有单独的线程来处理过程输出
以下是简单测试应用程序的JNLP文件:
<jnlp spec="1.0+" codebase="http://localhost:8080/test" href="test.jnlp">
<information>
<title>Test Process Builder</title>
<vendor>Test Vendor</vendor>
<homepage href="http://www.test.com" />
<description>Launches Test Process Builder</description>
<description kind="short">Test Process Builder</description>
<shortcut online="true">
<desktop />
</shortcut>
</information>
<security>
<all-permissions/>
</security>
<update check="always" policy="always"/>
<resources>
<java href="http://java.sun.com/products/autodl/j2se" version="1.7.0_21+"/>
<property name="jnlp.versionEnabled" value="false"/>
<jar href="lib/test.jar" download="eager" main="true"/>
</resources>
<application-desc main-class="netmedical.util.TestProcessBuilder">
<argument>/bin/sh</argument>
<argument>-c</argument>
<argument>/usr/sbin/system_profiler SPHardwareDataType</argument>
</application-desc>
</jnlp>
我也尝试过将JNLP转换为引用本地文件系统:
codebase="file://localhost/Library/Tomcat/webapps/test"
并发生相同的行为。
启动Mac应用程序包时,唯一的区别必须与运行时环境有关,但我不知道这可能是什么区别。
是否有问题: