如何解决Linux僵尸进程没有被Java ProcessBuilder终止
我有一个带有控制器的Java Spring REST API,该控制器运行带有ProcessBuilder类的linux命令
。该命令是生成的“查找”命令
问题是使用几天后,我在托管服务器中发现了许多未终止的进程。我不知道他们为什么还在那里而没有终结或被摧毁。 (我用ps -ef命令检查了
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());
最后,您应该返回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);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。