刚刚从 Java 11 迁移到 Java 14
以下代码现在在 Linux 机器上失败:
String linux_exe = System.getProperty("user.dir") + '/' + "fpcalc_arm32";
List<String> params = new ArrayList();
params.add(linux_exe);
params.add("-plain");
params.add("-length");
params.add(submittedSongLength);
params.add(file.getPath());
Process p = Runtime.getRuntime().exec(params.toArray(new String[1]));
带有堆栈跟踪
Cannot run program "/mnt/system/config/Apps/SongKong/songkong/fpcalc_arm32": error=0, Failed to exec spawn helper: pid: 13998, exit value: 127
java.io.IOException: Cannot run program "/mnt/system/config/Apps/SongKong/songkong/fpcalc_arm32": error=0, Failed to exec spawn helper: pid: 13998, exit value: 127
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1128)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1071)
at java.base/java.lang.Runtime.exec(Runtime.java:590)
at java.base/java.lang.Runtime.exec(Runtime.java:449)
at com.jthink.songkong.analyse.acoustid.AcoustId.generateFingerprint(AcoustId.java:217)
at com.jthink.songkong.analyse.acoustid.AcoustId.createAcoustIdFingerprint(AcoustId.java:106)
Java 14 中发生了什么变化会导致这种情况?
我使用 java 14 在 Windows 上运行了等效代码,并且运行正常。但我在这台使用 Java 11 和 Java 14 的 Unix 机器上重试了相同的代码库,并且可以确认 Java 11 始终有效并且 Java 14 始终失败
我发现了这个问题,我在 Openjdk Bugs 数据库上遇到了这些问题
为Runtime.exec提供在linux上使用posix_spawn的方法
和
将 Linux 上默认的进程启动机制更改为 posix_spawn
本质上,在 Java 11 中,Linux 使用
vfork
来启动进程,但到了 Java 13,它现在使用 posix_spawn
。
posix_spawn
实际上需要一个名为 jspawnhelper
的程序,该程序位于 jre/lib
中。在我的例子中,它存在,但它没有执行权限,这是因为我使用 jlink
构建一个只有我需要的系统模块的 jre,但我在 Windows (我的主开发环境)上创建它。
call "C:\Program Files\AdoptOpenJDK\jdk-11.0.6.10-hotspot\bin\jlink" --module-path="C:\Code\jthink\SongKong\linux_jdk\jmods" --add-modules java.desktop,java.datatransfer,java.logging,java.management,java.naming,java.net.http,java.prefs,java.scripting,java.sql,jdk.management,jdk.unsupported,jdk.scripting.nashorn --output C:\code\jthink\songkong\linuxjre
Windows 不理解 Linux 执行权限,当我部署应用程序时,我对
jre/bin
中的可执行文件设置了执行权限,但不知道 jre/lib
中存在任何可执行文件。更改 jspawnhelper 的执行权限可以修复该问题。
另一种解决方法是添加以下 java 选项:
-Djdk.lang.Process.launchMechanism=vfork
同一错误消息的另一个相当奇特的原因可能是操作系统在程序运行时更新了 java 发行版,然后程序尝试执行外部进程。这发生在我们部署的服务器上,客户端更新了 java 发行版。解决方案就是重新启动服务。
我还不能投票,所以我写它作为答案。 bmurauer 对我的情况是正确的。 JavaRuntime 在 Java 应用程序 (openhab) 运行时由操作系统在后台更新。重新启动 openhab 解决了我的问题。