【问题标题】:Any way to "reboot" the JVM?有什么办法可以“重启”JVM?
【发布时间】:2016-08-02 23:58:06
【问题描述】:

有没有办法重启JVM?如实际上并没有退出,而是关闭并重新加载所有类,然后从顶部运行 main?

【问题讨论】:

  • 您可能想提供更多背景知识。你想完成什么?
  • @HotLicks 是的,因为我们都是天生的专家,对吧?
  • @ununiform - 因为它需要对 JVM 有相当深入的了解,并且它与操作系统的接口才能做到这一点。

标签: java jvm


【解决方案1】:

您最好的选择可能是在循环中运行 java 解释器,然后退出。例如:

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

如果您希望能够完全重启或关闭,您可以测试退出状态:

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

在 java 程序中,您可以使用 System.exit(0) 表示您要“重新启动”,并使用 System.exit(1) 表示您要停止并保持停止状态。

【讨论】:

    【解决方案2】:

    IBM 的 JVM 有一个称为“可重置”的功能,它允许您有效地执行您所要求的操作。

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

    除了 IBM JVM,我认为不可能。

    【讨论】:

      【解决方案3】:

      不是真正的“重启”,而是:

      您可以构建自己的类加载器并使用它加载所有类(引导程序除外)。然后,当您要“重新启动”时,请确保执行以下操作:

      1. 结束您已打开并正在使用您的课程的所有线程。
      2. 释放您创建的任何窗口/对话框/小程序(UI 应用程序)。
      3. 关闭/处置任何其他需要 GC 根/操作系统资源的对等资源(数据库连接等)。
      4. 丢弃自定义的类加载器,创建它的另一个实例并重新加载所有类。您可以通过对文件中的类进行预处理来优化这一步,这样您就不必再次访问代码库了。
      5. 致电您的主要入口。

      此过程(在某种程度上)在网络服务器中“热交换”网络应用程序时使用。

      但请注意,静态类成员和 JVM“全局”对象(由不受您控制的 GC 根访问的对象)将保留。例如,Locale.setLocale() 会影响 Locale 上的静态成员。由于 Locale 类是由系统类加载器加载的,因此不会“重新启动”。这意味着如果没有明确清除,在 Locale.setLocale() 中使用的旧 Locale 对象将在之后可用。

      另一个途径是类的检测。但是,由于我对此知之甚少,因此我不愿提供建议。

      Explanation about hot deploy with some examples

      【讨论】:

        【解决方案4】:

        如果您在应用程序服务器中工作,它们通常带有内置的热部署机制,当您重新部署应用程序(Web 应用程序、企业应用程序)时,它们会重新加载应用程序中的所有类。

        否则,您将不得不研究商业解决方案。 Java Rebel (http://www.zeroturnaround.com/javarebel/) 就是这样一种选择。

        【讨论】:

          【解决方案5】:

          AFAIK 没有这样的方法。

          请注意,如果有办法做到这一点,它将高度依赖当前加载的代码来正确释放所有持有的资源,以提供优雅的重启(想想文件、socket/tcp/http/database 连接、线程等)。

          一些应用程序,如 Jboss AS,在控制台上捕获 Ctrl+C 并提供正常关闭,关闭所有资源,但这是特定于应用程序的代码,而不是 JVM 功能。

          【讨论】:

            【解决方案6】:

            我使用 JMX 做类似的事情,我将使用 JMX “卸载”一个模块,然后“重新加载”它。在幕后,我确信他们使用的是不同的类加载器。

            【讨论】:

              【解决方案7】:

              嗯,我目前有这个,它运行良好,并且完全独立于操作系统。唯一必须工作的事情:执行没有任何路径/等的java进程,但我认为这也可以修复。

              除了 RunnableWithObject 和 restartMinecraft() 之外的小代码都来自stackoverflow :)

              你需要这样称呼它:

              restartMinecraft(getCommandLineArgs());
              

              所以它的基本作用是:

              1. 生成一个新进程并将其存储在 p 变量中
              2. 创建两个 RunnableWithObject 实例并将进程对象填充到它们的数据值中,然后启动两个线程,当它有可用数据时它们只打印 inputStream 和 errorStream 直到进程退出
              3. 等待进程退出
              4. 打印有关进程退出的调试消息
              5. 以进程的退出值终止(非必要)

              是的,它是直接从我的 Minecraft 项目中提取的:)

              代码:

              Tools.isProcessExited() 方法:

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

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

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

              Aaaa 最后是 RunnableWithObject 类:

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

              祝你好运:)

              【讨论】:

                【解决方案8】:

                在 JavaX 中很容易:您可以使用标准函数 nohupJavax()restart()

                【讨论】:

                  猜你喜欢
                  • 2011-05-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-02-25
                  • 2016-01-20
                  • 1970-01-01
                  • 2023-02-06
                  • 2014-07-01
                  相关资源
                  最近更新 更多