How to kill subprocesses of a Java process?
Asked Answered
M

7

7

I am creating a process P1 by using Process P1= Runtime.exec(...). My process P1 is creating another process say P2, P3....

Then I want to kill process P1 and all the processes created by P1 i.e. P2, P3...

P1.destroy() is killing P1 only, not its sub processes.

I also Googled it and found it's a Java bug: https://bugs.java.com/bugdatabase/view_bug?bug_id=4770092

Does anyone have any ideas on how to do it?

Methadone answered 4/5, 2011 at 7:11 Comment(2)
Can you get the process id of the subprocess? Maybe you can kill them by Runtime.exec() again.Rotunda
As of 12th of May 2017, the bug has been closed as "Won't Fix". I suggest to rely on native OS calls for closing subprocesses.Odilia
H
3

Yes, it is a Bug, but if you read the evaluation the underlying problem is that it is next to impossible to implement "kill all the little children" on Windows.

The answer is that P1 needs to be responsible for doing its own tidy-up.

Huddleston answered 4/5, 2011 at 7:32 Comment(0)
I
2

I had a similar issue where I started a PowerShell Process which started a Ping Process, and when I stopped my Java Application the PowerShell Process would die (I would use Process.destroy() to kill it) but the Ping Process it created wouldn't.

After messing around with it this method was able to do the trick:

private void stopProcess(Process process) {
    process.descendants().forEach(new Consumer<ProcessHandle>() {
        @Override
        public void accept(ProcessHandle t) {
            t.destroy();
        }
    });
    process.destroy();
}

It kills the given Process and all of its sub-processes.

PS: You need Java 9 to use the Process.descendants() method.

Incondensable answered 6/1, 2021 at 23:47 Comment(0)
D
1

Java does not expose any information on process grandchildren with good reason. If your child process starts another process then it is up to the child process to manage them.

I would suggest either

  • Refactoring your design so that your parent creates/controls all child processes, or
  • Using operating system commands to destroy processes, or
  • Using another mechanism of control like some form of Inter-Process Communication (there are plenty of Java libraries out there designed for this).

Props to @Giacomo for suggesting the IPC before me.

Dorsum answered 4/5, 2011 at 7:29 Comment(0)
A
0

Is you writing other processes' code or they are something you cannot change?

If you can, I would consider modifying them so that they accept some kind of messages (even through standard streams) so they nicely terminate upon request, terminating children if they have, on their own.

I don't find that "destroying process" something clean.

Antecedents answered 4/5, 2011 at 7:17 Comment(0)
S
0

if it is bug, as you say then you must keep track pf process tree of child process and kill all child process from tree when you want to kill parent process you need to use data structure tree for that, if you have only couple of process than use list

Seppuku answered 4/5, 2011 at 7:19 Comment(0)
M
0

To kill sub processes, java process instance will not guaranty to kill all related sub processes. Till java 8, we don't have proper method to get pid of process so you need to do following to get pid first and then use taskkill for windows and pkill for linux. From java 9, you don't need to worry about pid. it would be simply process.pid() and use that pid to kill the process. like taskkill /PID pid /F /T.

/**
 * Method to destroy process and its children manually for both windows and linux
 * @param process
 * @param commandLine
 */
private static void destroyProcess(Process process, String commandLine) {
    if (Platform.getOS().contains(Platform.OS_WIN32)) {
        commandLine = commandLine.replace("\\", "\\\\");
        // calling process.destroy() doesn't kill its subprocesses properly so getting id
        // of the launched process through its commandLine and terminating it by running
        // taskkill command with /T flag
        String command = "powershell -command \" & {$proc_id=(Get-CimInstance Win32_Process -Filter \"\"\"CommandLine='" //$NON-NLS-1$
                + commandLine + "\"' AND ParentProcessId = " + getProcessId() //$NON-NLS-1$
                + "\"\"\"\").ProcessId;;taskkill /PID $proc_id /F /T}";
        try {
            Process p = Runtime.getRuntime().exec(command);
            while (!p.waitFor(1, TimeUnit.SECONDS));
        } catch (IOException | InterruptedException e) {
            //log exception
        }
    }
    else {
        //linux case
        try {
            if (process.getClass().getName().equals("java.lang.UNIXProcess")) {
                Field f = process.getClass().getDeclaredField("pid");
                f.setAccessible(true);
                int pid = (int) f.getLong(process);
                f.setAccessible(false);
                Process p = Runtime.getRuntime().exec("pkill -P " + pid);
                while (!p.waitFor(1, TimeUnit.SECONDS));
            }
        } catch (Exception e) {
            //log exception
        }
    }
}

 /**
 * Method to get process id of running application
 * @return process id
 */
private static int getProcessId() {
    RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
    // Get name representing the running Java virtual machine.
    // It returns something like 6460@USER. Where the value
    // before the @ symbol is the PID.
    String jvmName = bean.getName();
    return Integer.valueOf(jvmName.split("@")[0]);
}
Manly answered 24/8, 2023 at 10:48 Comment(0)
R
-1

Because the Runtime.exec() return a instance of Process, you can use some array to store their reference and kill them later by Process.destroy().

Rotunda answered 4/5, 2011 at 7:21 Comment(1)
The question speaks about processes there are children of the one executed by JavaAntecedents

© 2022 - 2024 — McMap. All rights reserved.