Reputation: 71
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?
Upvotes: 7
Views: 7579
Reputation: 111
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]);
}
Upvotes: 0
Reputation: 308
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.
Upvotes: 2
Reputation: 719689
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.
Upvotes: 3
Reputation:
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
Props to @Giacomo for suggesting the IPC before me.
Upvotes: 1
Reputation: 3742
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().
Upvotes: -1
Reputation: 12064
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
Upvotes: 0
Reputation: 11413
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.
Upvotes: 0