linux zombie进程未使用java processbuilder终止

h9a6wy2h  于 2021-07-12  发布在  Java
关注(0)|答案(1)|浏览(426)

我有一个javaspringrestapi,它带有一个运行带有processbuilder类的linux命令的控制器
. 该命令是生成的“find”命令
问题是我在托管服务器上使用了五天后发现了很多未终止的进程。我不知道为什么他们还在那里,没有结束或毁灭(我用ps-ef命令检查过)
下面是我的runcmd函数:

public static final BufferedReader runCmd(String cmd) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder();
        processBuilder.command("bash", "-c",  cmd);

        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();

        BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));

        int ret = process.waitFor();
        return output;
}

有没有办法让sur不再留下任何进程?
更新
这个问题只来自具有非常大的输出流(std output)的命令,感谢@duncg的提示
由于这个输出很重要,我不能忽略它。我得想办法把它吃掉。
你知道如何使用可运行线程吗?
谢谢

r7s23pms

r7s23pms1#

您的命令是否生成大量输出?僵尸的原因可能很简单,cmd在stdout中写入了大量输出,而流在bufferedreader中阻塞。
您可以通过将重定向添加到null来测试这种情况,只需在cmd的末尾附加“>/dev/null”。这将丢弃子进程输出,并意味着bufferedreader没有充满未读数据/阻塞子进程。

processBuilder.command("bash", "-c",  cmd+" > /dev/null");

如果这解决了僵尸问题,您可以恢复重定向并 ProcessBuilder 将输出重定向到文件(在调用 start() ),或者您需要添加一个线程以在生成io时使用它。

Path tmpdir = Path.of(System.getProperty("java.io.tmpdir"));
Path out = tmpdir.resolve("stdout.log");
processBuilder.redirectErrorStream(true);
processBuilder.redirectOutput(out.toFile());

最后,您应该返回out文件供调用者检查,或者可以返回 Files.newBufferedReader(out) .
如果您没有像上面那样使用重定向到文件,这将使用线程将输出捕获到内存缓冲区中。注意,如果不重定向err->out,也需要为stderr复制:

Process p = pb.start();
ByteArrayOutputStream stdout = new ByteArrayOutputStream(8192);
new Thread(() -> copy(p.getInputStream(), stdout), "STDOUT").start();
int rc = p.waitFor();
byte[] sour = stdout.toByteArray()

使用方法:

private static void copy(InputStream in, OutputStream buf)
{
    try(var autoClose = in; var autoClose2 = buf)
    {
        in.transferTo(buf);
    }
    catch(IOException io)
    {
        throw new UncheckedIOException(io);
    }
}

相关问题