为什么它保持lib/模块锁定?

2022-09-02 02:00:07

当我从Java 9应用程序启动任何第三方应用程序时,例如记事本(但您可以采用其他任何内容),然后退出Java应用程序:

import java.io.*;

public class LaunchNotepad {
  public static void main(String[] args) throws IOException {
    Runtime.getRuntime().exec(new String[] {"C:\\Windows\\notepad.exe"});
  }
}

启动的第三方应用程序不断锁定Java 9的文件。这使得具有私有 JRE 的 Java 应用程序很难自行更新,因为原始目录(包含 JRE)无法重命名。以下是ProcessExplorer(Sysinternals)的屏幕截图:lib\modules

Screenshot of ProcessExplorer showing the notepad process launched by Java 9

这听起来像是一个 Java 9 错误(报告为 JDK-8194734),但是有没有一个变通办法可以在 Windows 上启动应用程序而不锁定 lib\modules 文件,例如,通过使用外部(代理)应用程序,该应用程序只是将传递的参数作为应用程序启动?


答案 1

修复了这个错误。这是否算作解决方法?:)

否则,一些解决方法确实是可能的。

解决方法 1:使用 awt。桌面

浏览Java源代码,我发现可以调用我们。awt.DesktopShellExecute

遗憾的是,此方法不允许传递命令行参数。您可以将临时批处理文件写入磁盘并启动它作为解决方法。

import java.io.*;
import java.awt.Desktop;

public class LaunchNotepad {
  public static void main(String[] args) throws IOException {
    File program = new File("C:\\Windows\\notepad.exe");
    Desktop.getDesktop().open(program);
  }
}

解决方法 2:使用 PsExec 作为代理

SysInternals PsExec 不会将文件继承到使用它启动的进程中。请记住使用参数,否则 PsExec 本身将保存该文件。-d

不能用作代理,因为它始终继承句柄。cmd.exe

解决方法 3:创建自己的代理

您需要使用以下两个 WINAPI 之一:CreateProcess(指定 )或 ShellExecutebInheritHandles=FALSE


答案 2

如果您有Oracle Java支持合同,则应通过支持渠道询问何时进行修复。

更新 - 根据 https://bugs.openjdk.java.net/browse/JDK-8194734,目前的答案可能是“当Java 11发布时”。但Oracle可能会决定将修复程序向后移植到Java 9和10。

如果您真的迫切需要修复,请考虑执行以下操作:

  1. 下载 OpenJDK 源代码并构建您自己的 JVM。

  2. 找出错误的位置。你似乎知道它是什么,所以不难弄清楚在哪里看。

  3. 开发该错误的修复程序。

  4. 将修复程序作为修补程序贡献给 OpenJDK 项目。

这将增加在标准代码库和由其生成的发行版中更快地解决问题的可能性。它还将为您提供内部测试和愿意使用“固定”JVM的客户的解决方案。

我提到了一个可能的解决方法,涉及重新编写代码,而您断然拒绝了。还有其他的。AFAIK没有不涉及工作的方法,无论哪种方式。


推荐