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?
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é.
La JVM D'IBM a une fonctionnalité appelée "réinitialisable" qui vous permet de faire efficacement ce que vous demandez.
Autre que la JVM IBM, Je ne pense pas que ce soit possible.
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:
- Terminez tous les threads que vous avez ouverts et utilisez vos classes.
- éliminez toute fenêtre / boîte de dialogue / Applet que vous avez créée (application D'interface utilisateur).
- fermez / éliminez toute autre ressource peered affamée de ressources GC root / OS (connexions de base de données, etc.).
- 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.
- 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
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.
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.
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.
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:
- génère un nouveau processus et le stocke dans la variable p
- 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
- attend la sortie du processus
- affiche le message de débogage à propos de la sortie du processus
- 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 :)
Il est facile de JavaX: Vous pouvez utiliser les fonctions standard nohupJavax() ou restart().