Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a Java process hang from Gradle when sub-process is still open?

If a process created in java creates a sub-process, but then returns, the JVM hangs, but with no process id.

Example application below (requires Windows and Java 7)

import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.nio.file.Files;

public class SubProcessHang {

    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "start", "notepad.exe");
        File output = Files.createTempFile("output", "txt").toFile();
        builder.redirectError(Redirect.to(output));
        builder.redirectOutput(Redirect.to(output));
        Process process = builder.start();
        process.waitFor();
        int exitValue = process.exitValue();
        System.out.println("Process exit value:: " + exitValue);
        System.out.println("Output file length:: " + output.length());
        System.exit(exitValue);
    }
}

When the application runs, it creates three processes: java --> cmd --> notepad cmd immediately returns and java calls System.exit(0), which kills the java process. But notepad is still there, and, when run from gradle (or eclipse for that matter,) the JVM hangs around until that process goes away, not returning it's return value.

So the children process is still alive but the parent process has been partially killed, but is now stranded forever.

The build.gradle script to reproduce this

apply plugin: 'java'
apply plugin: 'application'
mainClassName = "SubProcessHang"

Execute 'gradle run' and get this output:

C:\HangDemo>gradlew run
:compileJava
:processResources UP-TO-DATE
:classes
:run
Process exit value:: 0
Output file length:: 0
> Building 75% > :run

I know it must have something to do with how the java processes are created, but I have no idea what to do.

What can I do short of getting the ID of the running java process and killing all sub-processes in a shutdown hook?

like image 815
w25r Avatar asked Feb 20 '14 20:02

w25r


Video Answer


2 Answers

The docs for Process say

By default, the created subprocess does not have its own terminal or console. All its standard I/O (i.e. stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream(). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.

http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html

Maybe your process is creating stdout or stderr output. Try draining the InputStream and the ErrorStream.

like image 153
Perryn Fowler Avatar answered Oct 11 '22 22:10

Perryn Fowler


I would say that this answer might help with getting the sub-process IDs and this one - with killing them in Windows environment.

Hope that helps!

like image 1
dnl-blkv Avatar answered Oct 12 '22 00:10

dnl-blkv