web-dev-qa-db-fra.com

Un moyen de "redémarrer" la machine virtuelle?

Est-il possible de redémarrer la JVM? En tant que dans ne pas quitter réellement, mais fermez et rechargez toutes les classes, et exécutez principal du haut?

29
Alex

Votre meilleur choix est probablement d'exécuter l'interpréteur Java dans une boucle et de quitter. Par exemple:

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

Si vous souhaitez avoir 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 souhaitez "redémarrer" et System.exit (1) pour indiquer que vous souhaitez vous arrêter et rester arrêté.

17
Andru Luvisi

La machine virtuelle Java d'IBM dispose d'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

À part la machine virtuelle IBM, je ne pense pas que ce soit possible.

7
DustinB

Pas un vrai "redémarrage" mais:

Vous pouvez créer votre propre chargeur de classes et charger toutes vos classes (sauf un bootstrap) avec. Ensuite, lorsque vous souhaitez "redémarrer", assurez-vous de procéder comme suit:

  1. Mettez fin aux discussions que vous avez ouvertes et qui utilisent vos classes.
  2. Éliminez toute fenêtre/boîte de dialogue/applet que vous avez créé (application d'interface utilisateur).
  3. Fermez/supprimez toutes les autres ressources homologues affamées des ressources racine/système d'exploitation du GC (connexions à la base de données, etc.).
  4. Jetez votre chargeur de classes personnalisé, créez-en une autre 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 de la "permutation à chaud" d'applications Web dans des serveurs Web.

Notez cependant que les membres de classe statiques et les objets "globaux" de la machine virtuelle Java (ceux auxquels accède une racine de GC qui n'est pas sous votre contrôle) resteront. Par exemple, Locale.setLocale () affecte un membre statique à Locale. Comme la classe Locale est chargée par le chargeur de classes du système, elle ne sera pas "redémarrée". Cela signifie que l'ancien objet Locale utilisé dans Locale.setLocale () sera disponible après s'il n'a pas été explicitement nettoyé.

Une autre voie à suivre est l'instrumentation des classes. Cependant, comme je ne connais que très peu de choses, j’hésite à donner des conseils.

Explication sur le déploiement à chaud avec quelques exemples

2
Ran Biron

Si vous travaillez sur un serveur d'applications, ils sont généralement doté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 chercher des solutions commerciales. Java Rebel ( http://www.zeroturnaround.com/javarebel/ ) est l'une de ces options.

1
Jack Leow

Autant que je sache, il n'y a pas de telle façon. 

Notez que s’il existait un moyen de le faire, cela dépendrait beaucoup du code chargé actuel pour libérer correctement toutes les ressources conservées afin de permettre un redémarrage en douceur (pensez aux fichiers, aux connexions socket/tcp/http/database, aux threads, etc.). ).

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

0
Miguel Ping

C'est facile en JavaX: vous pouvez utiliser les fonctions standard nohupJavax () ou restart () .

0
Stefan Reich

Eh bien, j'ai actuellement cela, 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 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, en gros, c'est:

  1. Crée un nouveau processus et le stocke dans la variable p
  2. Crée deux occurrences RunnableWithObject et remplit l'objet de processus dans leur valeur de données, puis lance deux threads; ils ne font qu'imprimer les entréesStream et errorStream lorsqu'il dispose de données jusqu'à la sortie du processus
  3. Attend la fin du processus
  4. affiche un message de débogage sur la sortie du processus
  5. Termine avec la valeur de sortie du processus (pas nécessaire)

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

Le code:

Méthode Tools.isProcessExited ():

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

Méthode Tools.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());
    }

Méthode Tools.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
therealfarfetchd

Je fais quelque chose de similaire en utilisant JMX, je «déchargerai» un module en utilisant JMX, puis je le «rechargerai». En coulisse, je suis sûr qu'ils utilisent un chargeur de classe différent.

0
Javamann