web-dev-qa-db-fra.com

Comment obtenir un hook d'arrêt pour exécuter un processus lancé à partir d'Eclipse

J'ai un crochet d'arrêt dans mon application (créé à l'aide de Runtime.getRuntime().addShutdownHook). Cependant, si je lance l'application depuis Eclipse, le hook d'arrêt ne s'exécute pas lorsqu'il est arrêté. 

Je pense que cela est dû au fait qu’Eclipse envoie au processus l’équivalent d’un signal d’abattage forcé, qui ne provoque pas l’exécution du crochet d’arrêt (équivalent de taskkill/F sous Windows ou de kill -p sous Linux), bien que Je ne suis pas absolument sûr.

Est-ce que quelqu'un sait comment contourner cela? J'utilise Windows (Vista) et j'ai le sentiment que cela pourrait être un problème spécifique à Windows, mais je ne suis pas sûr.

53
Neil

J'ai utilisé le hack suivant à la fin de ma méthode principale pour résoudre le problème:

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);
}  
23
Sairam R

Tout d’abord, votre demande se termine-t-elle ou la mettez-vous de force? Si vous le forcez à le terminer (via le bouton d'arrêt), ce rapport de bogue Eclipse explique en détail pourquoi cela pourrait ne pas fonctionner.

Si vous ne le faites pas, vous avez peut-être raison de dire qu'il s'agit d'un comportement spécifique à Windows. Je suis sur un Mac, donc je ne peux pas confirmer, désolé. Cependant, je peux vous dire que le programme de test suivant fait ​​exécute les crochets d'arrêt comme prévu.

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." );
    }
}

Les Javadocs pour Runtime # addShutdownHook mentionnent que les crochets d'arrêt ne s'exécutent pas lorsque la JVM est abandonnée, ni abandonnée normalement, donc encore une fois, vos hypothèses sont correctes. Cela étant dit, voici quelques choses à essayer. Encore une fois, désolé, je ne peux pas confirmer ces informations à l’avance - pas de Windows ici. (Heureusement!)

  • Assurez-vous que la machine virtuelle Java n'inclut pas l'option - Xrs . Cela a un effet secondaire sur les crochets d'arrêt.
  • Essayez de lancer la machine virtuelle Java à l’aide de l’option - serveur ou - client . D'après mon expérience, le comportement de la casse Edge peut être affecté par le choix du mode VM. (Surtout en ce qui concerne le threading - du moins sur Mac.)
  • Lancez-vous votre application sous un profileur ou similaire? Chargement de bibliothèques natives?
  • Avez-vous une erreur fatale et la manquez-vous? Par exemple, OutOfMemoryError ou similaire?
  • Essayez de cocher/décocher l'option Lancer en arrière-plan à partir de la boîte de dialogue de votre application Run Configuration dans Eclipse.
  • Dernier point mais non le moindre: Invoke System.exit () manuellement si vous en avez la possibilité. :)
12
JLR

Voici un script que vous pouvez exécuter en dehors d’Eclipse pour répertorier les processus disponibles exécutés sous Eclipse que vous pourriez tuer.

#!/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'"
5
Jason Axelson

Sous Windows, arrêtez gracieusement une application Java de manière standard, vous devez envoyer Ctrl + C à cela. Cela ne fonctionne qu'avec les applications de la console, mais Eclipse utilise javaw.exe au lieu de Java.exe. Pour résoudre ce problème, ouvrez la configuration de lancement, l'onglet JRE et sélectionnez "Alternative JRE:". La zone de groupe "Exécutable Java" apparaît et permet de saisir le fichier exécutable "Java".

Nous avons maintenant besoin d'un programme externe pour envoyer Ctrl-C à un processus avec une console cachée. J'ai trouvé des indices ici et ici . Notre programme se connecte à la console du processus souhaité et envoie l'événement à la console.

#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;
}

Test du programme 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);
    }

}

Terminant le:

C:\>killsoft.exe 10520

Sortie du programme de test dans Eclipse:

pid: 10520
Sleeping...
Shutting down...
1
basin

Je ne sais pas comment résoudre ce problème, mais IntelliJ a ajouté un bouton distinct à sa boîte de dialogue "Exécuter", qui arrête le VM de manière à appeler les crochets d'arrêt. Leur débogueur n'a pas cette fonctionnalité.

1
Javamann

Sairam est ici, en appelant System.exit (0) , nous pouvons mettre fin à la machine virtuelle Eclipse et voir les résultats du hook

0
Shashank

Je suis coincé dans Websphere pour le moment et je ne vois pas ce que je cherche . Mais je me souviens d'avoir une option de configuration d'exécution liée au lancement de l'application dans la même machine virtuelle . est-il possible de lancer votre application Java dans le même VM que le VM Eclipse?

Mais l'option me fait perdre la tête.

0
guyumu