2008-11-03 18 views
26

¿Hay alguna manera de reiniciar la JVM? Como en realidad no salir, pero cerrar y volver a cargar todas las clases, y ejecutar principal desde la parte superior?¿Hay alguna manera de "reiniciar" la JVM?

+0

Es posible que desee dar un poco más de fondo. ¿Qué está tratando de lograr? –

+0

@HotLicks sí porque todos somos expertos en todo, ¿no? – ununiform

+0

@ununiform - Porque requiere un conocimiento bastante íntimo de la JVM y su interfaz con el sistema operativo para hacerlo bien. –

Respuesta

16

Su mejor opción es probablemente ejecutar el intérprete de Java dentro de un ciclo, y simplemente salir. Por ejemplo:

#!/bin/sh 
while true 
do 
    java MainClass 
done 

Si desea que la capacidad de reiniciar o apagar por completo, usted podría probar el estado de salida:

#!/bin/sh 
STATUS=0 
while [ $STATUS -eq 0 ] 
do 
    java MainClass 
    STATUS=$? 
done 

Dentro del programa Java, puede utilizar System.exit (0) a indique que desea "reiniciar" y System.exit (1) para indicar que desea detenerse y permanecer detenido.

0

AFAIK no hay tal manera.

Tenga en cuenta que, si hubiera una manera de hacerlo, dependerá en gran medida del código cargado actualmente para liberar correctamente todos los recursos retenidos a fin de proporcionar un reinicio elegante (piense en archivos, conexiones socket/tcp/http/database , hilos, etc.).

Algunas aplicaciones, como Jboss AS, capturan Ctrl + C en la consola y proporcionan un cierre elegante, cerrando todos los recursos, pero este es un código específico de la aplicación y no una característica de JVM.

1

Si trabaja en un servidor de aplicaciones, generalmente vienen con mecanismos de implementación en caliente que recargarán todas las clases en su aplicación (aplicación web, aplicación empresarial) cuando la vuelva a implementar.

De lo contrario, tendrá que buscar soluciones comerciales. Java Rebel (http://www.zeroturnaround.com/javarebel/) es una de esas opciones.

0

Hago algo similar con JMX, voy a 'descargar' un módulo usando JMX y luego 'recargarlo'. Detrás de escena, estoy seguro de que están usando un cargador de clases diferente.

2
No

un verdadero "reinicio", sino:

Usted puede construir su propio cargador de clases y cargar todas sus clases (excepto una) de arranque con él. Luego, cuando desee "reiniciar", asegúrese de hacer lo siguiente:

  1. Finalice los hilos que haya abierto y esté utilizando sus clases.
  2. Deseche cualquier ventana/diálogo/applet que haya creado (aplicación UI).
  3. Cerrar/eliminar cualquier otro recurso picante hambriento de los recursos de GC/GC (conexiones de bases de datos, etc.).
  4. Deseche el cargador de clases personalizado, cree otra instancia y vuelva a cargar todas las clases. Probablemente pueda optimizar este paso preprocesando las clases desde los archivos para que no tenga que acceder nuevamente a la base de código.
  5. Llame a su punto principal de entrada.

Este procedimiento se usa (en cierta medida) mientras se intercambian "webapps" en servidores web.

Nota embargo, miembros de la clase estáticos y objetos JVM "globales" (los que se accede por una raíz GC que no está bajo su control) se mantendrá. Por ejemplo, Locale.setLocale() afecta a un miembro estático en Locale. Como la clase Locale es cargada por el cargador de clases del sistema, no se "reiniciará". Eso significa que el viejo objeto Locale que se utilizó en Locale.setLocale() estará disponible después si no se limpian de forma explícita.

Sin embargo, otra ruta a tomar es la instrumentación de las clases. Sin embargo, dado que sé muy poco de eso, dudo en ofrecer consejos.

Explanation about hot deploy with some examples

0

Bueno, actualmente tiene esto, que funciona perfectamente, y completamente independiente del sistema operativo. La única cosa que debe trabajar: ejecutar el proceso java sin ninguna ruta/etc, pero creo que esto también puede ser fijado.

Los pedazos pequeños de código son todos de stackoverflow excepto RunnableWithObject y restartMinecraft() :)

Es necesario llamarlo así:

restartMinecraft(getCommandLineArgs()); 

Así lo hace, básicamente, es:

  1. Genera un nuevo Proceso y lo almacena en la variable p
  2. Realiza dos instancias de RunnableWithObject y rellena objeto de proceso en su valor de datos, a continuación, inicia dos hilos, que acaba de imprimir el flujoEntrada y flujoError cuando tiene datos disponibles hasta que se sale del proceso
  3. espera que el proceso para salir
  4. impresiones mensaje de depuración acerca de salida del proceso
  5. termina con el valor de salida del proceso (no es necesario)

Y sí se tira directamente de mi proyecto Minecraft :)

el código:

Tools.isProcessExited) método (:

public static boolean isProcessExited(Process p) { 
    try { 
     p.exitValue(); 
    } catch (IllegalThreadStateException e) { 
     return false; 
    } 
    return true; 
} 

Tools.restartMinecraft) método (:

public static void restartMinecraft(String args) throws IOException, InterruptedException { 
//Here you can do shutdown code etc 
     Process p = Runtime.getRuntime().exec(args); 
     RunnableWithObject<Process> inputStreamPrinter = new RunnableWithObject<Process>() { 

      @Override 
      public void run() { 
       // TODO Auto-generated method stub 
       while (!Tools.isProcessExited(data)) { 
        try { 
         while (data.getInputStream().available() > 0) { 
          System.out.print((char) data.getInputStream().read()); 
         } 
        } catch (IOException e) { 
        } 
       } 
      } 
     }; 
     RunnableWithObject<Process> errorStreamPrinter = new RunnableWithObject<Process>() { 

      @Override 
      public void run() { 
       // TODO Auto-generated method stub 
       while (!Tools.isProcessExited(data)) { 
        try { 
         while (data.getErrorStream().available() > 0) { 
          System.err.print((char) data.getErrorStream().read()); 
         } 
        } catch (IOException e) { 
        } 
       } 
      } 
     }; 

     inputStreamPrinter.data = p; 
     errorStreamPrinter.data = p; 

     new Thread(inputStreamPrinter).start(); 
     new Thread(errorStreamPrinter).start(); 
     p.waitFor(); 
     System.out.println("Minecraft exited. (" + p.exitValue() + ")"); 
     System.exit(p.exitValue()); 
    } 

Tools.getCommandLineArgs() Método:

public static String getCommandLineArgs() { 
    String cmdline = ""; 
    List<String> l = ManagementFactory.getRuntimeMXBean().getInputArguments(); 
    cmdline += "java "; 
    for (int i = 0; i < l.size(); i++) { 
     cmdline += l.get(i) + " "; 
    } 
    cmdline += "-cp " + System.getProperty("java.class.path") + " " + System.getProperty("sun.java.command"); 

    return cmdline; 
} 

aaaaand finalmente la clase RunnableWithObject:

package generic.minecraft.infinityclient; 

public abstract class RunnableWithObject<T> implements Runnable { 
    public T data; 
} 

Buena suerte :)

Cuestiones relacionadas