Any way to “reboot” the JVM?

后端 未结 8 1003
难免孤独
难免孤独 2020-12-05 17:46

Is there any way to reboot the JVM? As in don\'t actually exit, but close and reload all classes, and run main from the top?

相关标签:
8条回答
  • Well, I currently have this, it works perfectly, and completely OS-independent. The only thing that must work: executing the java process without any path/etc, but I think this can also be fixed.

    The little code pieces are all from stackoverflow except RunnableWithObject and restartMinecraft() :)

    You need to call it like this:

    restartMinecraft(getCommandLineArgs());
    

    So what it basically does, is:

    1. Spawns a new Process and stores it in the p variable
    2. Makes two RunnableWithObject instances and fills the process object into their data value, then starts two threads, they just print the inputStream and errorStream when it has available data until the process is exited
    3. Waits for the process to exit
    4. prints debug message about process exit
    5. Terminates with the exit value of the process(not necessary)

    And yes it is directly pulled from my minecraft project:)

    The code:

    Tools.isProcessExited() method:

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

    Tools.restartMinecraft() method:

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

    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 finally the RunnableWithObject class:

    package generic.minecraft.infinityclient;
    
    public abstract class RunnableWithObject<T> implements Runnable {
        public T data;
    }
    

    Good luck :)

    0 讨论(0)
  • 2020-12-05 18:15

    Not a real "reboot" but:

    You can build your own class loader and load all your classes (except a bootstrap) with it. Then, when you want to "reboot", make sure you do the following:

    1. End any threads that you've opened and are using your classes.
    2. Dispose any Window / Dialog / Applet you've created (UI application).
    3. Close / dispose any other GC root / OS resources hungry peered resource (database connections, etc).
    4. Throw away your customized class loader, create another instance of it and reload all the classes. You can probably optimize this step by pre-processing the classes from files so you won't have to access the codebase again.
    5. Call your main point of entry.

    This procedure is used (to some extent) while "hot-swapping" webapps in web servers.

    Note though, static class members and JVM "global" objects (ones that are accessed by a GC root that isn't under your control) will stay. For example, Locale.setLocale() effects a static member on Locale. Since the Locale class is loaded by the system class loader, it will not be "restarted". That means that the old Locale object that was used in Locale.setLocale() will be available afterward if not explicitly cleaned.

    Yet another route to take is instrumentation of classes. However, since I know little of it, I'm hesitant to offer advice.

    Explanation about hot deploy with some examples

    0 讨论(0)
提交回复
热议问题