it-swarm.com.de

Irgendeine Möglichkeit, die JVM neu zu starten?

Gibt es eine Möglichkeit, die JVM neu zu starten? Wie in nicht wirklich beenden, aber alle Klassen schließen und neu laden und von oben nach oben laufen?

29
Alex

Ihre beste Wette ist wahrscheinlich, den Java-Interpreter in einer Schleife auszuführen und einfach zu beenden. Zum Beispiel:

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

Wenn Sie einen Neustart oder das vollständige Herunterfahren wünschen, können Sie den Exitstatus testen:

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

Innerhalb des Java-Programms können Sie System.exit (0) verwenden, um anzugeben, dass Sie einen Neustart durchführen möchten, und System.exit (1), um anzuzeigen, dass Sie stoppen und angehalten bleiben möchten.

17
Andru Luvisi

Die JVM von IBM verfügt über eine Funktion mit dem Namen "rücksetzbar", mit der Sie effektiv das tun können, was Sie möchten.

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

Abgesehen von der IBM JVM glaube ich nicht, dass dies möglich ist.

7
DustinB

Kein echter "Neustart", aber:

Sie können Ihren eigenen Klassenladeprogramm erstellen und alle Ihre Klassen (außer einem Bootstrap) damit laden. Wenn Sie dann "neu starten" möchten, stellen Sie sicher, dass Sie Folgendes tun:

  1. Beenden Sie alle Threads, die Sie geöffnet haben und Ihre Klassen verwenden.
  2. Entsorgen Sie jedes von Ihnen erstellte Fenster/Dialog/Applet (UI-Anwendung).
  3. Schließen/Entsorgen Sie alle anderen GC-Root-/OS-Ressourcen, die auf die Peer-Ressourcen (Datenbankverbindungen usw.) zugreifen.
  4. Werfen Sie Ihren benutzerdefinierten Klassenlader weg, erstellen Sie eine weitere Instanz und laden Sie alle Klassen erneut. Sie können diesen Schritt wahrscheinlich optimieren, indem Sie die Klassen aus Dateien vorverarbeiten, sodass Sie nicht erneut auf die Codebase zugreifen müssen.
  5. Rufen Sie Ihren Haupteinstiegspunkt an.

Dieses Verfahren wird (zum Teil) beim "Hot Swapping" von Webapps in Webservern verwendet.

Beachten Sie jedoch, dass statische Klassenmitglieder und "globale" Objekte der JVM (Objekte, auf die von einem GC-Stamm, auf den Sie keinen Einfluss haben) zugreifen können. Beispielsweise wirkt Locale.setLocale () auf Locale mit einem statischen Member. Da die Locale-Klasse vom System-Class-Loader geladen wird, wird sie nicht "neu gestartet". Das bedeutet, dass das alte Locale-Objekt, das in Locale.setLocale () verwendet wurde, danach verfügbar ist, wenn es nicht ausdrücklich bereinigt wird.

Ein weiterer Weg ist die Instrumentierung von Klassen. Da ich jedoch wenig davon weiß, zögere ich, Ratschläge zu erteilen.

Erklärung zu Hot Deploy mit einigen Beispielen

2
Ran Biron

Wenn Sie auf einem Anwendungsserver arbeiten, verfügen sie normalerweise über integrierte Hot-Deployment-Mechanismen, die alle Klassen Ihrer Anwendung (Web-App, Unternehmens-App) bei der erneuten Bereitstellung neu laden.

Ansonsten müssen Sie sich kommerzielle Lösungen ansehen. Java Rebel ( http://www.zeroturnaround.com/javarebel/ ) ist eine solche Option.

1
Jack Leow

AFAIK gibt es nicht. 

Beachten Sie, dass es in diesem Fall in hohem Maße von dem aktuell geladenen Code abhängen würde, wenn alle angehaltenen Ressourcen ordnungsgemäß freigegeben werden, um einen ordnungsgemäßen Neustart zu ermöglichen ).

Einige Anwendungen wie Jboss AS erfassen Ctrl + C auf der Konsole und bieten ein ordnungsgemäßes Herunterfahren und Schließen aller Ressourcen. Dies ist jedoch anwendungsspezifischer Code und keine JVM-Funktion.

0
Miguel Ping

In JavaX ist das einfach: Sie können die Standardfunktionen nohupJavax () oder restart () verwenden.

0
Stefan Reich

Nun, ich habe das derzeit, es funktioniert perfekt und ist völlig unabhängig vom Betriebssystem. Das einzige, was funktionieren muss: Ausführen des Java-Prozesses ohne Pfad/etc, aber ich denke, das kann auch behoben werden.

Die kleinen Codestücke stammen alle von stackoverflow, außer RunnableWithObject und restartMinecraft () :)

Sie müssen es so nennen:

restartMinecraft(getCommandLineArgs());

Was es im Grunde so macht, ist:

  1. Erzeugt einen neuen Prozess und speichert ihn in der Variablen p
  2. Erzeugt zwei RunnableWithObject-Instanzen und füllt das Prozessobjekt in ihren Datenwert. Dann werden zwei Threads gestartet. Sie geben nur inputStream und errorStream aus, wenn Daten verfügbar sind, bis der Prozess beendet wird
  3. Wartet, bis der Prozess beendet ist
  4. gibt eine Debugmeldung über den Prozessende aus
  5. Wird mit dem Exit-Wert des Prozesses beendet (nicht erforderlich)

Und ja, es wird direkt aus meinem Minecraft-Projekt gezogen :)

Der Code:

Tools.isProcessExited () - Methode:

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

Tools.restartMinecraft () -Methode:

    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 () - Methode:

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

Aaaaund schließlich die RunnableWithObject-Klasse:

package generic.minecraft.infinityclient;

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

Viel Glück :)

0

Ich mache etwas Ähnliches mit JMX, ich werde ein Modul mit JMX "entladen" und anschließend "neu laden". Ich bin mir sicher, dass sie hinter den Kulissen einen anderen Klassenlader verwenden.

0
Javamann