2009-02-13 15 views
49

Tengo un gancho de cierre en mi aplicación (creado usando Runtime.getRuntime().addShutdownHook). Sin embargo, si ejecuto la aplicación desde Eclipse, cuando se apaga, el gancho de cierre no se ejecuta.Cómo obtener shutdown hook para ejecutar en un proceso iniciado desde Eclipse

Creo que esto se debe a que Eclipse envía al proceso el equivalente de una señal de destrucción de fuerza, que no hace que se ejecute el gancho de desconexión (equivalente a taskkill/F en Windows o kill -p en Linux) , aunque no estoy absolutamente seguro

¿Alguien sabe cómo evitar esto? Estoy ejecutando Windows (Vista) y tengo la sensación de que puede tratarse de un problema específico de Windows, pero no estoy seguro.

+0

No haga funcionar su aplicación desde dentro de Eclipse? –

+0

Creo que la sugerencia de @ mattb es buena, porque la mayoría de los programas deberían ejecutarse fuera del IDE en algún momento. Por cierto, IntelliJ IDEA tiene un botón para esto: http://stackoverflow.com/questions/4727536/. –

+2

@ TimBüthe, Bueno, pero no es útil cuando estamos haciendo rápidos ciclos de prueba de código-depuración-código-prueba-depuración ... – Pacerier

Respuesta

1

No estoy seguro de cómo solucionar esto, pero IntelliJ agregó un botón por separado a su diálogo 'Ejecutar' que apagará la máquina virtual de una manera que llama a los ganchos de apagado. Su depurador no tiene esta característica.

11

En primer lugar, ¿está terminando su aplicación o la está forzando a la finalización? Si lo está forzando a la finalización (mediante el botón de detener), este Eclipse bug report tiene detalles sobre por qué esto podría no funcionar.

En su defecto, puede ser correcto acerca de que se trata de un comportamiento específico de Windows. Estoy en una Mac así que no puedo confirmar, lo siento. Sin embargo, puedo decirle que el siguiente programa de prueba hace ejecutar los ganchos de apagado como se esperaba.

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

El Javadocs para Runtime#addShutdownHook mencionan que los ganchos de cierre no se ejecutan cuando la JVM se aborta, no terminó normalmente, por lo que una vez más, usted es probablemente correcta en sus suposiciones. Dicho esto, aquí hay algunas cosas que probar. De nuevo, lo siento, no puedo confirmar esto de antemano, no hay Windows aquí. (Gracias a Dios!)

  • Asegúrese de que la JVM no incluye la opción -Xrs. Esto tiene un side-effect en los ganchos de cierre.
  • Intente iniciar la JVM utilizando -servidor o -cliente opción. Según mi experiencia, el comportamiento de mayúsculas y minúsculas puede verse afectado por la elección del modo VM. (Especialmente con respecto a enhebrar, al menos en Mac.)
  • ¿Está iniciando su aplicación en un generador de perfiles o similar? Cargando cualquier biblioteca nativa?
  • ¿Estás recibiendo un error fatal y lo echas de menos? Por ejemplo, OutOfMemoryError o similar?
  • Intente marcar/desmarcar Inicie en la opción de fondo desde el cuadro de diálogo Configuración de la ejecución en Eclipse.
  • Por último pero no menos importante: Invoque System.exit() manualmente si tiene la oportunidad. :)
+1

¿Cómo supiste buscar la opción -Xrs? – Pacerier

0

estoy atascado en WebSphere en este momento, y no ven lo que estoy buscando. Pero sí recuerdo que eclipse tiene una opción de configuración de ejecución relacionada con el inicio de la aplicación en la misma máquina virtual. ¿Es posible que lance su aplicación java en la misma máquina virtual que la máquina virtual eclipse?

Pero la opción se me escapa.

23

que utiliza este truco al final de mi método principal para evitar el problema:

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); 
} 
+5

Nota: debe agregar manualmente la variable de entorno "RUNNING_IN_ECLIPSE" en la configuración de ejecución y establecer el valor en TRUE. –

+0

O simplemente puede hacer líneas sin if/else con el único propósito de depuración. –

+0

Esta solución no funciona si queremos probar el "apagado" de una aplicación ** de la consola que se está ejecutando a la mitad. – Pacerier

5

Aquí hay un script que puede ejecutar fuera de Eclipse para listar los procesos disponibles ejecuta en Eclipse que se podía matar.

#!/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'" 
+0

Hmm, pero matarlo es lo mismo que detenerlo a la fuerza, ¿verdad? Como tal, los ganchos de cierre no se ejecutarían. – Pacerier

+1

@Pacerier depende de la señal que use. El valor predeterminado es TERM que ejecutará los ganchos de apagado. 'kill -9' no ejecutará los ganchos de apagado. Más información: http://superuser.com/questions/107543/bash-man-page-kill-pid-vs-kill-9-pid –

0

Sai Ram es aquí, Llamando System.exit (0) que puede poner fin a JVM Eclipse y puede ver los resultados de gancho de cierre

0

En Windows para detener con gracia una aplicación Java de una manera estándar se necesita enviar Ctrl + C a él. Esto solo funciona con aplicaciones de consola, pero Eclipse usa javaw.exe en lugar de java.exe. Para solucionar esto, abra la configuración de inicio, la pestaña JRE y seleccione "JRE alternativo:". Aparece el cuadro de grupo "Ejecutable de Java" y permite ingresar el ejecutable alternativo "java".

Ahora necesitamos un programa externo para enviar Ctrl-C a un proceso con una consola oculta. Encontré sugerencias here y here. Nuestro programa se conecta a la consola del proceso deseado y envía el evento de la consola. programa Java

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

prueba:

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

} 

terminarlo:

C:\>killsoft.exe 10520 

salida del programa de prueba en Eclipse:

pid: 10520 
Sleeping... 
Shutting down... 
Cuestiones relacionadas