как я могу убить процесс Linux в java с помощью SIGKILL Process.destroy() делает SIGTERM

В Linux, когда я запускаю функцию уничтожения объекта java.lang.Process (который является типизированным java.lang.UNIXProcess ), он отправляет сигнал SIGTERM в процесс, есть ли способ убить его с помощью SIGKILL?


person ekeren    schedule 01.06.2010    source источник


Ответы (4)


Не используя чистую Java.

Самый простой вариант — использовать Runtime.exec() для запуска команды kill -9 <pid> в качестве внешнего процесса.

К сожалению, получить PID не так просто. Вам нужно будет либо использовать черную магию отражения для доступа к полю private int pid, либо возиться с выводом команды ps.

ОБНОВЛЕНИЕ - на самом деле есть другой способ. Создайте небольшую утилиту (программу на C, сценарий оболочки и т. д.), которая будет запускать реальное внешнее приложение. Закодируйте утилиту так, чтобы она запоминала PID дочернего процесса и устанавливала обработчик сигнала для SIGTERM, который будет SIGKILL дочернего процесса.

person Stephen C    schedule 01.06.2010
comment
Я могу сделать это так или в JNI, хотя я не горю желанием делать это таким образом, как узнать pid процесса, который вы хотите убить? - person ekeren; 01.06.2010
comment
Во-первых, спасибо за эти ответы. отражение и JNI/exec - мое последнее средство, интересно, может ли кто-нибудь найти более элегантный способ сделать это. - person ekeren; 01.06.2010
comment
Я также жестко отношусь к палачу оберток, на самом деле мой босс жестко относится к этому :), поэтому я понимаю, что нет прямого способа сделать это, о котором вы знаете. - person ekeren; 01.06.2010
comment
@ekeren - Правильно. Я полагаю, вы можете скачать исходники OpenJDK, изменить их и создать собственную JVM... но это еще худшая альтернатива. - person Stephen C; 01.06.2010
comment
Если вы собираетесь делать вызовы системной библиотеки, не делайте этого прямо в JNI... избавьте себя от некоторых головных болей и вместо этого делайте это в JNA. - person rob; 19.10.2013
comment
Не знаю, является ли он переносимым, но на Android Process.toString() выдает строку Process[pid=1234] - person Alexander Malakhov; 13.02.2014
comment
Хотя мне это неудобно, и в своем коде я решил возиться с выводом из ps :) - person Alexander Malakhov; 13.02.2014
comment
@AlexanderMalahov - Нет, это не переносимо, поскольку в javadoc для метода toString() не указан формат строки. Согласно исходному коду, для Oracle Java в Unix метод toString() для Process и UnixProcess не переопределяется из Object.toString(). То, что вы видите, (в лучшем случае) специфично для Android. - person Stephen C; 13.02.2014
comment
Взгляните на это сообщение, если вы можете использовать Java 1.8 - person Ercksen; 08.08.2015
comment
@Ercksen - Вы проверили собственный исходный код, чтобы увидеть, действительно ли принудительно означает SIGTERM? - person Stephen C; 09.08.2015
comment
Взгляните на это, и в пункте 5.21 вы можете смотрим как определяется сигнал: int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;. Итак, как видите, SIGTERM является сигналом по умолчанию, а SIGKILL используется при форсировании. Обратите внимание, что это только для класса UNIXProcess, но я считаю, что другие системы не будут вести себя по-другому. - person Ercksen; 09.08.2015
comment
Есть ли причина, по которой это должно работать для kill -9, но не для kill -2? Я обнаружил, что kill -2 не работает при вызове из java, но работает из оболочки. Подробности: stackoverflow.com/q/49522487/1054322 - person MatrixManAtYrService; 28.03.2018
comment
Этот вопрос не имеет для меня особого смысла. Во-первых, код, который якобы показывает, что вы выполняете kill -2 из Java, этого не делает. И закомментированный код не скомпилируется, потому что в Process нет атрибута pid. - person Stephen C; 28.03.2018

Стивен, его ответ правильный. Я написал то, что он сказал:

public static int getUnixPID(Process process) throws Exception
{
    System.out.println(process.getClass().getName());
    if (process.getClass().getName().equals("java.lang.UNIXProcess"))
    {
        Class cl = process.getClass();
        Field field = cl.getDeclaredField("pid");
        field.setAccessible(true);
        Object pidObject = field.get(process);
        return (Integer) pidObject;
    } else
    {
        throw new IllegalArgumentException("Needs to be a UNIXProcess");
    }
}

public static int killUnixProcess(Process process) throws Exception
{
    int pid = getUnixPID(process);
    return Runtime.getRuntime().exec("kill " + pid).waitFor();
}

Вы также можете получить pid следующим образом:

public static int getPID() {
  String tmp = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
  tmp = tmp.split("@")[0];
  return Integer.valueOf(tmp);
}
person Martijn Courteaux    schedule 01.06.2010
comment
в linux я запускаю команды через java (интерактивный процесс): nslookup -> google, это зависает процесс, и я не могу убить этот процесс. Итак, теперь я воспользовался вашим предложением, но он не завершает этот процесс, он просто зависает, и я не могу завершить свою программу. Я даже пытался убить pid вручную, но безрезультатно, что мне делать??? - person Space Rocker; 15.03.2013
comment
@Space Rocker: простое убийство отправляет SIGTERM. Убийство -9 посылает SIGKILL. Попробуйте kill -9 -1: это отправляет SIGKILL всем процессам в группе процессов, у которых pid › 1. Если это не убьет его, то ничего не убьет. Но это сработает. - person Csaba Toth; 10.04.2013
comment
Обязательно используйте второй способ получения PID. VisualVM делает то же самое. Первый способ - уродливый хак, он не кроссплатформенный и может не работать в будущих версиях Java. - person Espinosa; 03.07.2013
comment
@Espinosa - второй способ тоже не переносимый. В javadoc для getName говорится: Возвращенная строка имени может быть любой произвольной строкой, и реализация виртуальной машины Java может встроить в возвращаемую строку имени полезную информацию, зависящую от платформы. Примечание: может< /b> выбрать, означает, что он также может не делать этого. И нет спецификации того, как эта информация должна быть отформатирована. - person Stephen C; 13.02.2014
comment
Начиная с Java 9, вы можете просто вызвать process.pid(), чтобы получить идентификатор процесса. - person Luke Hutchison; 02.12.2020

Если вы знаете имя процесса, вы можете использовать pkill

Runtime.getRuntime().exec("pkill firefox").waitFor();
person user4757345    schedule 14.05.2015

Начиная с Java 1.8

вы можете вызвать метод destroyForcibly(), который по умолчанию вызывает метод destroy(), но, согласно документам Java, все подпроцессы, возвращаемые ProcessBuilder или Runtime.exec(), реализуют этот метод.

person Ercksen    schedule 22.07.2015
comment
К сожалению, в настоящее время реализация просто вызывает destroy(). См. здесь: bugs.openjdk.java.net/browse/JDK-8056139 - person Joe; 26.01.2016