Как заставить отключение завершить выполнение процесса, запущенного из Eclipse - PullRequest
53 голосов
/ 13 февраля 2009

В моем приложении есть хук отключения (созданный с использованием Runtime.getRuntime().addShutdownHook). Однако, если я запускаю приложение из Eclipse, когда оно выключается, ловушка выключения не выполняется.

Я думаю, это потому, что Eclipse отправляет в процесс эквивалент сигнала принудительного уничтожения, что не приводит к выполнению обработчика отключения (эквивалент для taskkill / F в Windows или kill -p в Linux), хотя я не совсем уверен.

Кто-нибудь знает, как это обойти? У меня Windows (Vista), и я чувствую, что это может быть проблема, специфичная для Windows, но я не уверен.

Ответы [ 7 ]

23 голосов
/ 12 марта 2009

Я использовал следующий хак в конце основного метода, чтобы обойти проблему:

if (Boolean.parseBoolean(System.getenv("RUNNING_IN_ECLIPSE"))) {
    System.out.println("You're using Eclipse; click in this console and " +
            "press ENTER to call System.exit() and run the shutdown routine.");
    try {
        System.in.read();
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.exit(0);
}  
12 голосов
/ 18 февраля 2009

Прежде всего, ваше приложение заканчивается или вы принудительно заканчиваете его? Если вы принудительно завершаете его (с помощью кнопки остановки), в этом отчете об ошибке Eclipse есть сведения о том, почему это может не работать.

В противном случае вы можете быть правы в том, что это специфичное для Windows поведение. Я на Mac, поэтому не могу подтвердить, извините. Тем не менее, я могу сказать вам, что следующая тестовая программа выполняет выполнение обработчиков завершения работы, как и ожидалось.

public class MyShutdownHook
{
    public static void main( String[] args )
    {
        System.out.println( "Entering main." );

        Runtime.getRuntime().addShutdownHook( 
            new Thread(
                new Runnable() {
                    public void run() {
                        System.out.println( "Shutdown hook ran." );
                    }   
                }
            )
        );

        System.out.println( "Exiting main." );
    }
}

В Javadocs для Runtime # addShutdownHook упоминается, что перехватчики завершения работы не запускаются, когда JVM прерывается, не завершается нормально, поэтому, опять же, вы, вероятно, правы в своих предположениях. Это, как говорится, вот несколько вещей, чтобы попробовать. Опять же, извините, я не могу подтвердить это заранее - здесь нет Windows. (Благословенно!)

  • Убедитесь, что JVM не включает опцию -Xrs . Это имеет побочный эффект на крюках отключения.
  • Попробуйте запустить JVM с помощью опции -server или -client . По моему опыту, поведение в крайнем случае может зависеть от выбора режима виртуальной машины. (Особенно в отношении потоков - по крайней мере, на Mac.)
  • Запускаете ли вы свое приложение под профилировщиком или чем-то подобным? Загрузка каких-либо собственных библиотек?
  • Вы получаете какую-то фатальную ошибку и упускаете ее? Например, OutOfMemoryError или подобное?
  • Попробуйте установить или снять флажок Запустить в фоновом режиме в диалоговом окне Запустить конфигурацию вашего приложения в Eclipse.
  • Последнее, но не менее важное: если у вас есть возможность, вызовите System.exit () вручную. :)
5 голосов
/ 23 марта 2012

Вот скрипт, который вы можете запустить за пределами Eclipse, чтобы вывести список доступных процессов, работающих в Eclipse, которые вы можете убить.

#!/bin/bash
set -o nounset                              # Treat unset variables as an error

PROCESSES=$(ps axo pid,ppid,command)

# Find eclipse launcher PID
LAUNCHER_PID=$(echo "$PROCESSES" | grep "/usr/lib/eclipse/eclipse" |grep -v "launcher"|awk '{print $1}')
echo "Launcher PID $LAUNCHER_PID"

# Find eclipse PID
ECLIPSE_PID=$(echo "$PROCESSES" | egrep "[[:digit:]]* $LAUNCHER_PID " | awk '{print $1}')
echo "Eclipse PID $ECLIPSE_PID"

# Find running eclipse sub-process PIDs
SUB_PROCESS=$(echo "$PROCESSES" | egrep "[[:digit:]]* $ECLIPSE_PID " | awk '{print $1}')

# List processes
echo
for PROCESS in $SUB_PROCESS; do
    DRIVER=$(ps --no-headers o pid,ppid,command $PROCESS | awk '{print $NF}')
    echo "$PROCESS $DRIVER"
done

echo "Kill a process using: 'kill -SIGTERM \$PID'"
1 голос
/ 18 августа 2017

В Windows, чтобы корректно остановить стандартное Java-приложение, вам необходимо отправить Ctrl + C . Это работает только с консольными приложениями, но Eclipse использует javaw.exe вместо java.exe. Чтобы решить эту проблему, откройте конфигурацию запуска, вкладку JRE и выберите «Альтернативный JRE:». Появляется групповое окно «Исполняемый файл Java», в котором можно ввести альтернативный исполняемый файл «Java».

Теперь нам нужна внешняя программа для отправки Ctrl-C процессу со скрытой консолью. Я нашел подсказки здесь и здесь . Наша программа подключается к консоли нужного процесса и отправляет событие консоли.

#include <stdio.h>
#include <windows.h>

int main(int argc, char* argv[])
{
    if (argc == 2) {
        unsigned pid = 0;
        if (sscanf_s(argv[1], "%u", &pid) == 1) {
            FreeConsole(); // AttachConsole will fail if we don't detach from current console
            if (AttachConsole(pid)) {
                //Disable Ctrl-C handling for our program
                SetConsoleCtrlHandler(NULL, TRUE);
                GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
                return 0;
            }
        }
    }

    return 1;
}

Тест Java-программы:

public class Shuthook {

    public static void main(final String[] args) throws Exception {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("Shutting down...");
            }
        });

        String sPid = ManagementFactory.getRuntimeMXBean().getName();
        sPid = sPid.substring(0, sPid.indexOf('@'));

        System.out.println("pid: " + sPid);
        System.out.println("Sleeping...");
        Thread.sleep(1000000);
    }

}

Завершение:

C:\>killsoft.exe 10520

Вывод тестовой программы в Eclipse:

pid: 10520
Sleeping...
Shutting down...
1 голос
/ 13 февраля 2009

Я не уверен, как это исправить, но IntelliJ добавил отдельную кнопку в их диалоговое окно «Выполнить», которое отключит виртуальную машину таким образом, что вызывает «Завершение работы». Их отладчик не имеет этой функции.

0 голосов
/ 25 сентября 2015

Сайрам прямо здесь. Вызвав System.exit (0) , мы можем завершить JVM затмения и увидеть результаты перехвата отключения

0 голосов
/ 18 февраля 2009

В данный момент я застрял в сети и не вижу, что ищу. Но я помню, что у Eclipse была опция конфигурации запуска, связанная с запуском приложения на той же виртуальной машине. Возможно ли, что вы запускаете Java-приложение на той же виртуальной машине, что и виртуальная машина eclipse?

Но вариант ускользает от меня.

...