如何杀死Java进程的子进程?

问题描述 投票:0回答:7

我正在使用

Process P1= Runtime.exec(...)
创建进程 P1。我的进程 P1 正在创建另一个进程,例如 P2、P3....

然后我想杀死进程 P1 以及 P1 创建的所有进程,即 P2、P3...

P1.destroy()
仅杀死 P1,而不杀死其子进程。

我也用Google搜索了一下,发现这是一个Java bug: http://bugs.sun.com/view_bug.do?bug_id=4770092

有人对如何做有任何想法吗?

java process runtime runtime.exec
7个回答
3
投票

是的,这是一个错误,但如果你阅读评估,就会发现根本问题是在 Windows 上实现“杀死所有小孩”几乎是不可能的。

答案是

P1
需要自己负责整理。


2
投票

我遇到了类似的问题,我启动了一个 PowerShell 进程,该进程启动了一个 Ping 进程,当我停止我的 Java 应用程序时,PowerShell 进程将会终止(我会使用

Process.destroy()
来终止它),但它创建的 Ping 进程不会.

经过一番尝试后,这个方法成功了:

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

它会杀死给定的进程及其所有子进程。

PS:您需要Java 9才能使用

Process.descendants()
方法。


1
投票

Java 没有公开任何有关进程孙子的信息,这是有充分理由的。如果您的子进程启动另一个进程,则由子进程来管理它们。

我建议其中之一

  • 重构您的设计,以便您的父进程创建/控制所有子进程,或者
  • 使用操作系统命令销毁进程,或者
  • 使用另一种控制机制,例如某种形式的进程间通信(有很多为此设计的 Java 库)。

感谢 @Giacomo 在我之前建议 IPC。


0
投票

您是否编写了其他进程的代码,或者它们是您无法更改的?

如果可以的话,我会考虑修改它们,以便它们接受某种消息(即使通过标准流),这样它们就可以根据请求很好地终止,如果有的话,可以自行终止。

我不认为“破坏过程”是干净的。


0
投票

如果它是错误,正如你所说,那么你必须跟踪子进程的进程树,并在你想杀死父进程时杀死树中的所有子进程 如果你只有几个进程而不是使用列表,你需要使用数据结构树


0
投票

为了杀死子进程,java进程实例不保证杀死所有相关的子进程。直到java 8,我们都没有正确的方法来获取进程的pid,因此您需要先执行以下操作来获取pid,然后对windows使用taskkill,对linux使用pkill。从java 9开始,你不需要担心pid。它只是 process.pid() 并使用该 pid 来终止进程。像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]);
}

-1
投票

因为 Runtime.exec() 返回 Process 的实例,您可以使用一些数组来存储它们的引用,并稍后通过 Process.destroy() 杀死它们。

© www.soinside.com 2019 - 2024. All rights reserved.