强制杀死子进程的 Java 工具/方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4912282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java tool/method to force-kill a child process
提问by Gilad Haimov
I am looking for a Java tool/package/library that will allow me to force-kill a child process.
我正在寻找一个 Java 工具/包/库,它可以让我强制杀死一个子进程。
This tool/package/library must work on Windows platform (mandatory). Support for Linux/Unix is desired.
此工具/包/库必须在 Windows 平台上运行(强制)。需要支持 Linux/Unix。
My Problem
我的问题
My Java code creates a child process that will simply not react to the standard Java way for killing a child process: process.destroy(), and, since I do not have the child's source code, I cannot program it to better handle termination requests.
我的 Java 代码创建了一个子进程,它不会对杀死子进程的标准 Java 方式做出反应:process.destroy(),而且,由于我没有子进程的源代码,我无法对其进行编程以更好地处理终止请求.
I have tried closing the child process' error input and output stream before calling destroy(), and for no effect.
我尝试在调用 destroy() 之前关闭子进程的错误输入和输出流,但没有效果。
I have even tried passing ctrlBreak signal (char=3) directly into child.getOutputStream(), and again have received the same results.
我什至尝试将 ctrlBreak 信号 (char=3) 直接传递给 child.getOutputStream(),并再次收到相同的结果。
The workaround I have finally managed to find was to:
我最终设法找到的解决方法是:
Obtain the child's PID upon its creation This can be done in Windows by diffing the process lists before and after the child's creation (
getRuntime().exec("tasklist /v")
)Use the child's PID to issue a force kill system command
in Windows:getRuntime().exec("taskkill /pid " + childPid + " /f")
在创建子进程时获取子进程的 PID 这可以在 Windows 中通过比较子进程创建前后的进程列表来完成 (
getRuntime().exec("tasklist /v")
)
在 Windows 中使用孩子的 PID 发出强制杀死系统命令:getRuntime().exec("taskkill /pid " + childPid + " /f")
But - this is complex code I have no desire to debug and maintain, plus the problem itself, I have no doubt, was previously encountered by many other java developers, which leads me to the hope that such a Java tool/package/library already exists.
但是 - 这是我不想调试和维护的复杂代码,加上问题本身,我毫不怀疑,以前许多其他 Java 开发人员都遇到过,这让我希望这样的 Java 工具/包/库已经存在。
I just don't know its name...
我只是不知道它的名字...
PS: My child process was created by Runtime.getRuntime().exec(cmd)
, but
I get the same behaviour using a ProcessBuilder.
PS:我的子进程是由创建的Runtime.getRuntime().exec(cmd)
,但我使用 ProcessBuilder 得到了相同的行为。
采纳答案by Stan
There is a leaner way to do this using Java JNA.
使用 Java JNA 有一种更精简的方法可以做到这一点。
This works definitely for Windows and Linux, i assume that you can do the same for other platforms too.
这绝对适用于 Windows 和 Linux,我假设您也可以对其他平台执行相同的操作。
The biggest problem of Java process handling is the lack of a method to get the process id of the process started with untime.getRuntime().exec().
Java 进程处理的最大问题是缺少一种方法来获取使用 untime.getRuntime().exec() 启动的进程的进程 ID。
Assuming you got the pid of a process, you always can start a kill -9 command in linux, or use similar ways to kill a process in windows.
假设你得到了一个进程的pid,你总是可以在linux中启动一个kill -9命令,或者在windows中使用类似的方法来杀死一个进程。
Here is a way to get the process id natively for linux (borrowed from the selenium framework, :) ), and with the help of JNA this also can be done for windows (using native Windows API calls).
这是一种为 linux 本地获取进程 id 的方法(从 selenium 框架借来,:)),并且在 JNA 的帮助下,这也可以为 windows 完成(使用本地 Windows API 调用)。
For this to work (for Windows) you first have to get the JNA Library at JAVA NATIVE ACCESS (JNA): Downloadsor get it from maven
为此(对于 Windows),您首先必须在JAVA NATIVE ACCESS (JNA):下载或从maven获取 JNA 库
Look at the following code, which will get the pid of a (in this example windows) program (most of the code is actually debris to get a working java program going):
看看下面的代码,它会得到一个(在这个例子中是windows)程序的pid(大部分代码实际上是碎片,让一个工作的java程序运行):
import com.sun.jna.*;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
static interface Kernel32 extends Library {
public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
public int GetProcessId(Long hProcess);
}
public static void main(String[] args) {
try {
Process p;
if (Platform.isWindows())
p = Runtime.getRuntime().exec("cmd /C ping msn.de");
else if (Platform.isLinux())
p = Runtime.getRuntime().exec("cmd /C ping msn.de");
System.out.println("The PID: " + getPid(p));
int x = p.waitFor();
System.out.println("Exit with exitcode: " + x);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static int getPid(Process p) {
Field f;
if (Platform.isWindows()) {
try {
f = p.getClass().getDeclaredField("handle");
f.setAccessible(true);
int pid = Kernel32.INSTANCE.GetProcessId((Long) f.get(p));
return pid;
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (Platform.isLinux()) {
try {
f = p.getClass().getDeclaredField("pid");
f.setAccessible(true);
int pid = (Integer) f.get(p);
return pid;
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
else{}
return 0;
}
}
Hope this helps, ;)...
希望这可以帮助, ;)...
回答by AlexR
I had solved such problem in past using the same method you are suggesting here: use taskkill for windows and kill -9 for Unix.
我过去曾使用您在此处建议的相同方法解决了此类问题:对 Windows 使用 taskkill,对 Unix 使用 kill -9。
On windows you can use alternatively WMI by either invoking script (VBS or JS) from Java or using one of interoperability libraries (JaWin, Jintegra, Jinterop etc.)
在 Windows 上,您可以通过从 Java 调用脚本(VBS 或 JS)或使用互操作性库之一(JaWin、Jintegra、Jinterop 等)来替代使用 WMI。
I do not think that this solution is so complicated as you are afraid. I think it is not more than 50 code lines.
我不认为这个解决方案像你害怕的那样复杂。我认为不超过 50 行代码。
Good luck.
祝你好运。
回答by Guillermo81
For windows using jna 3.5.1
对于使用 jna 3.5.1 的窗口
try {
Process p = Runtime.getRuntime.exec("notepad");
Field f = p.getClass().getDeclaredField("handle");
f.setAccessible(true);
long handLong = f.getLong(p);
Kernel32 kernel = Kernel32.INSTANCE;
WinNT.HANDLE handle = new WinNT.HANDLE();
handle.setPointer(Pointer.createConstant(handLong));
int pid = kernel.GetProcessId(handle);
System.out.print(pid);
} catch (Throwable e) {
}