Un moyen de "redémarrer" la JVM?

Est - il possible de redémarrer la JVM? Comme dans ne quittez pas réellement, mais fermez et rechargez toutes les classes, et exécutez main à partir du haut?

26
demandé sur rob199 2008-11-03 20:20:05

8 réponses

Votre meilleur pari est probablement d'exécuter l'interpréteur java dans une boucle, et juste quitter. Par exemple:

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

Si vous voulez la possibilité de redémarrer ou d'arrêter complètement, vous pouvez tester l'état de sortie:

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

Dans le programme java, vous pouvez utiliser System.exit (0) pour indiquer que vous voulez "redémarrer", et le système.exit(1) pour indiquer que vous voulez arrêter et rester arrêté.

17
répondu Andru Luvisi 2008-11-03 18:12:20

La JVM D'IBM a une fonctionnalité appelée "réinitialisable" qui vous permet de faire efficacement ce que vous demandez.

Http://publib.boulder.ibm.com/infocenter/cicsts/v3r1/index.jsp?topic=/com.ibm.cics.ts31.doc/dfhpj/topics/dfhpje9.htm

Autre que la JVM IBM, Je ne pense pas que ce soit possible.

7
répondu DustinB 2008-11-03 18:08:56

Pas un vrai "redémarrage" mais:

Vous pouvez créer votre propre chargeur de classe et charger toutes vos classes (sauf un bootstrap) avec. Ensuite, lorsque vous voulez "redémarrer", assurez-vous de faire ce qui suit:

  1. Terminez tous les threads que vous avez ouverts et utilisez vos classes.
  2. éliminez toute fenêtre / boîte de dialogue / Applet que vous avez créée (application D'interface utilisateur).
  3. fermez / éliminez toute autre ressource peered affamée de ressources GC root / OS (connexions de base de données, etc.).
  4. jetez votre chargeur de classe personnalisé, créez une autre instance et rechargez toutes les classes. Vous pouvez probablement optimiser cette étape en pré-traitant les classes à partir de fichiers afin de ne plus avoir à accéder à la base de code.
  5. appelez votre point d'entrée principal.

Cette procédure est utilisée (dans une certaine mesure) lors du "hot-Swapps" webapps dans les serveurs web.

Notez cependant que les membres de classe statiques et les objets "globaux" JVM (ceux qui sont accessibles par une racine GC qui n'est pas sous votre contrôle) séjour. Par exemple, les paramètres Régionaux.setLocale() affecte un membre statique sur les paramètres régionaux. Puisque la classe Locale est chargée par le chargeur de classe système, elle ne sera pas "redémarrée". Cela signifie que l'ancien objet Locale qui a été utilisé dans Locale.setLocale() sera disponible par la suite s'il n'est pas explicitement nettoyé.

Une autre voie à suivre est l'instrumentation des classes. Cependant, comme je sais peu de choses, j'hésite à offrir des conseils.

Explication sur le déploiement à chaud avec certains exemples

2
répondu Ran Biron 2008-11-04 05:41:46

Si vous travaillez dans un serveur d'applications, ils sont généralement équipés de mécanismes de déploiement à chaud intégrés qui rechargent toutes les classes de votre application (application web, application d'entreprise) Lorsque vous la redéployez.

Sinon, vous devrez rechercher des solutions commerciales. Java Rebel ( http://www.zeroturnaround.com/javarebel/) est l'une de ces options.

1
répondu Jack Leow 2008-11-03 18:12:16

AFAIK il n'y a pas un tel moyen.

Notez que s'il y avait un moyen de le faire, cela dépendrait fortement du code chargé actuel pour libérer correctement toutes les ressources détenues afin de fournir un redémarrage gracieux (pensez aux fichiers, aux connexions socket/tcp/http/base de données, aux threads, etc.).

Certaines applications, comme Jboss AS, capturent Ctrl + C sur la console et fournissent un arrêt gracieux, fermant toutes les ressources, mais il s'agit d'un code spécifique à l'application et non d'une fonctionnalité JVM.

0
répondu Miguel Ping 2008-11-03 18:07:09

Je fais quelque chose de similaire en utilisant JMX, je vais "décharger" un module en utilisant JMX puis le "recharger". Dans les coulisses, je suis sûr qu'ils utilisent un chargeur de classe différent.

0
répondu Javamann 2008-11-03 20:28:20

Eh bien, je l'ai actuellement, cela fonctionne parfaitement, et complètement indépendant du système D'exploitation. La seule chose qui doit fonctionner: exécuter le processus java sans aucun chemin / etc, mais je pense que cela peut aussi être corrigé.

Les petits morceaux de code proviennent tous de stackoverflow sauf RunnableWithObject et restartMinecraft ():)

Vous devez l'appeler comme ceci:

restartMinecraft(getCommandLineArgs());

Donc ce qu'il fait fondamentalement, c'est:

  1. génère un nouveau processus et le stocke dans la variable p
  2. marques deux instances RunnableWithObject et remplit l'objet process dans leur valeur de données, puis démarre deux threads, ils impriment simplement inputStream et errorStream quand il a des données disponibles jusqu'à la sortie du processus
  3. attend la sortie du processus
  4. affiche le message de débogage à propos de la sortie du processus
  5. se termine par la valeur de sortie du processus(non nécessaire)

Et oui, il est directement tiré de mon projet minecraft:)

Le code:

Outils.méthode isProcessExited ():

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

Outils.méthode restartMinecraft ():

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

Outils.méthode getCommandLineArgs ():

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

Aaaaet enfin la classe RunnableWithObject:

package generic.minecraft.infinityclient;

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

Bonne chance :)

0
répondu therealfarfetchd 2014-06-01 13:59:09

Il est facile de JavaX: Vous pouvez utiliser les fonctions standard nohupJavax() ou restart().

0
répondu Stefan Reich 2016-08-02 15:58:06