Ich habe bereits im Internet gesucht, und die Frage process.waitFor() never returns zeigt an, dass es oft ein Problem mit Prozessen ist, dass ihre Stdout oder stderr nicht gelesen werden.Process.waitFor hängt, obwohl stdout und stderr lesen
Wir verwenden ProcessBuilder
mit redirectOutput
und redirectError
dies zu erreichen, und ich denke, dass wir auf der sicheren Seite sein sollte, finden Sie in der folgenden Methode, die wir Prozesse verwenden, um auszuführen:
public static void execute(String directory, long timeout, File out, File err, String... command) throws InterruptedException, IOException {
LOGGER.log(Level.INFO, String.format("executing command %s (%s)", Arrays.toString(command), timeout > 0 ? String.format("timeout = %,d[ms]", timeout) : "no timeout"));
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out);
if(out == err) {
builder.redirectErrorStream(true);
} else {
builder.redirectError(err);
}
long time = System.currentTimeMillis();
Process process = builder.start();
try {
LOGGER.log(Level.FINE, "waiting for process");
boolean exited = process.waitFor(timeout, TimeUnit.MILLISECONDS);
if(!exited) {
LOGGER.log(Level.WARNING, "timeout reached, trying to destroy ...");
exited = destroy(silent, process); // Helper method to destroy processes
}
long duration = System.currentTimeMillis() - time;
int exitValue = process.exitValue();
LOGGER.log(Level.INFO, "execution finished in " + duration + "[ms] => " + exitValue);
} catch (InterruptedException | Error | RuntimeException e) {
LOGGER.log(Level.SEVERE, "execution failed", e);
throw e;
}
}
Dennoch ist das Problem, dass es hängt an der process.waitFor(timeout, TimeUnit.MILLISECONDS)
Anruf, obwohl der Prozess leicht innerhalb der Zeitüberschreitung beendet sein sollte.
Die Logging-Ausgabe ist
Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute
INFO: executing command [java, -Xmx8G, -XX:+UseG1GC, -XX:+CrashOnOutOfMemoryError, -jar, MetricCalc.jar] (timeout = 14,400,000[ms])
Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute
FINE: waiting for process
(erkennen, dass keine execution finished
Linie noch geschrieben wird)
Die err
Datei liest
... Things we write to std.err ...
Finished Metrics
und die wichtigste Methode der MetricCalc sieht aus wie
public static void main(String[] args) {
.... do some stuff ...
System.err.println("Finished Metrics");
}
was anzeigt, dass das Lesen gut funktioniert, die letzte Zeile des Java-Programms wurde ausgeführt und der Prozess sollte beendet sein.
Jeder, der eine Idee hat, warum der Prozess nicht beendet wird/hängt immer noch an Process.waitFor()
?
* ".... und der Prozess sollte beendet sein." * - vorausgesetzt, der Kindprozess funktioniert so, wie Sie es erwarten. Überprüfen Sie, ob der untergeordnete Prozess tatsächlich beendet wurde. z.B. mit "ps -efl" oder ähnlichem. –
@StephenC: Ich kann es immer noch mit 'ps -efl | finden grep "java -Xmx8G" ', was anzeigt, dass es nicht beendet wurde. Noch habe ich keine Ahnung, warum dies der Fall ist, da die allerletzte Codezeile von MetricCalc (das Java-Programm, das als Prozess ausgeführt wird) ausgeführt wurde ... –
Oh, es kam mir gerade in den Sinn: Wahrscheinlich MetricCalc Es laufen einige Nicht-Deamon-Threads, die verhindern, dass die Anwendung beendet wird ... Das muss ich testen ... –