Java ProcessBuilder 限制

Java ProcessBuilder Limits

我有一个 Java 程序通过套接字连接到本地服务器,如果 Java 检测到它不是 运行.因此,如果 Java 未连接到服务器,那么我将使用 ProcessBuilder 启动它:

new ProcessBuilder(new String[]{"/bin/bash", "-c", "./start_server"}).start();

这会启动服务器,并运行大约 4 分钟,直到服务器进程没有响应。有趣的是,如果我发送更多命令,则发生这种情况所需的时间会更少。我想知道我是否遇到了 ProcessBuilder 的限制,可能使用了太多内存。我在服务器端将通信打印到服务器,因为这是从 ProcessBuilder 调用的,我假设它被定向到其他地方,这就是问题所在。

您必须阅读输出(即使您只是将其丢弃),包括 stdout 和 stderr。否则输出缓冲区将填满导致奇怪的行为。

最简单的方法是重定向到位桶(假设 Java 1.7+):

File bitbucket;

if (isWindows()) {
    bitbucket = new File("NUL");
} else {
    bitbucket = new File("/dev/null");
}

Process process = new ProcessBuilder("/bin/bash", "-c", "./start_server")
                  .redirectOutput(ProcessBuilder.Redirect.appendTo(bitbucket))
                  .redirectError(ProcessBuilder.Redirect.appendTo(bitbucket))
                  .start();

但是如果你必须使用 Java 1.6 或更低版本,你必须自己动手。这是我在我的项目中使用的:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class StreamConsumer
{
    private final InputStream stream;

    private StreamConsumer(InputStream is)
    {
        this.stream = is;
    }

    private Runnable worker()
    {
        return new Worker();
    }

    private class Worker implements Runnable
    {
        @Override
        public void run()
        {
            try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
                while (br.readLine() != null) {
                    /* No one cares */
                }
            } catch (IOException ioe) {
                /* No one cares */
            }
        }
    }

    public static void consume(InputStream stream, String label)
    {
        Thread t = new Thread(new StreamConsumer(stream).worker(), label);
        t.setPriority(Thread.MIN_PRIORITY);
        t.start();
    }
}

你可以这样称呼它:

Process process = new ProcessBuilder("/bin/bash", "-c", "./start_server")
                      .start();

StreamConsumer.consume(process.getInputStream(), "STDOUT");
StreamConsumer.consume(process.getErrorStream(), "STDERR");

或者像这样:

Process process = new ProcessBuilder("/bin/bash", "-c", "./start_server")
                      .redirectErrorStream(true)
                      .start();

StreamConsumer.consume(process.getInputStream(), "STDOUT/STDERR");

请注意,ProcessBuilder 构造函数采用 String...(可变参数),而不是 String[](尽管您可以根据需要手动创建和传递 String[]