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

发布于 2024-11-05 06:38:50 字数 389 浏览 4 评论 0原文

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

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

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

我也用谷歌搜索了一下,发现这是一个Java错误: https://bugs.java.com/bugdatabase/view_bug?bug_id=4770092

有人对如何做到这一点有任何想法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

岁月打碎记忆 2024-11-12 06:38:50

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

答案是P1需要负责自己的整理工作。

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.

残龙傲雪 2024-11-12 06:38:50

我遇到了类似的问题,我启动了一个 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() 方法。

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.

土豪我们做朋友吧 2024-11-12 06:38:50

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

我建议要么

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

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

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.

归属感 2024-11-12 06:38:50

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

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

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

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.

往事风中埋 2024-11-12 06:38:50

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

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

嗳卜坏 2024-11-12 06:38:50

要杀死子进程,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]);
}

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]);
}
烛影斜 2024-11-12 06:38:50

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

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().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文