java - 使用 Java ProcessBuilder 未终止 Linux 僵尸进程

标签 java processbuilder zombie-process

我有一个 java Spring REST API,带有一个使用 ProcessBuilder 类运行 Linux 命令的 Controller

。该命令是生成的“查找”命令

问题是,使用几天后,我发现托管服务器中有很多未终止的进程。我不知道为什么它们还在那里,没有结束或摧毁。 (我用 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;
}

有没有办法确保没有留下更多进程?

更新

问题仅来自具有非常大的输出流(标准输出)的命令,感谢您的提示@DuncG

由于这个输出很重要,我不能忽视它。我必须找到一种方法来消耗它。

关于如何使用可运行线程来做到这一点有什么想法吗?

谢谢

最佳答案

您的命令是否会生成大量输出?僵尸的原因可能只是 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());

最后你应该返回输出文件供调用者检查,或者可以返回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);
    }
}

关于java - 使用 Java ProcessBuilder 未终止 Linux 僵尸进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63468663/

相关文章:

java - 使用 java ProcessBuilder 从批处理文件运行 python 脚本不起作用

ruby-on-rails - 使用每个 block 打印所有僵尸的名称

javascript - 如何使用zombie测试<input type ="hidden">

java - 使用 MS Access 数据库中的数据填充 JTable 的代码

java - 比较给定期间内的日期

java - 问题 ProcessBuilder 运行脚本 sh

java - 使用 Process Builder 从 Java 运行 python

java - 如何使用java计算sql中表的一列中的不同值

java - 反转单链表