在运行时确定JVM可执行文件的位置

24

在运行时如何获取当前正在运行的JVM可执行文件的位置? 我想使用ProcessBuilder类将另一个JVM实例化为子进程。

我知道有java.home系统属性,但这并不指定JVM可执行文件的位置。 我明白我可以像这样做来获取路径:

System.getProperties().getProperty("java.home") + File.pathSeparator + "bin" + File.pathSeparator + "java"

由于Windows可执行文件的名称为java.exe而不是java,因此这段代码不是平台独立的。 有没有一种方法可以获取JVM可执行文件的路径,并考虑到每个平台的特殊性?


1
JAVA_HOME指向JDK而不是JRE。因此,当用户没有安装JDK时,您就会遇到麻烦。另外,即使我有JDK,也没有环境变量,但仍然一切正常。在Windows上,您可以将“.exe”拖放到要运行的程序文件名上。 - Joey
通过java.home系统属性,我指的不是环境变量,而是存在于System.getProperties()中的属性。我已经验证了JRE具有java.home系统属性。在Windows中,.exe扩展名是可选的,这一点很有用。 - Samad Lotia
你可以按照第一个评论所说的做,并在Windows上假设“bin/java.exe”,在其他平台上假设“bin/java”。还要考虑“javaw.exe”,这取决于你想做什么。 - Paul Jowett
(仅适用于Windows)这里有一种“有趣”的方法来检索它。获取JVM pid,启动VBScript以提取相应的路径:http://www.rgagnon.com/javadetails/java-get-running-jvm-path.html - RealHowTo
嗯,你在这里从未接受过答案,有什么特别的原因吗? - GhostCat
5个回答

13

您可以始终使用os.name来检查用户是否在运行Windows。这将适用于OS X,Linux和Windows。

String jvm_location;
if (System.getProperty("os.name").startsWith("Win")) {
    jvm_location = System.getProperties().getProperty("java.home") + File.separator + "bin" + File.separator + "java.exe";
} else {
    jvm_location = System.getProperties().getProperty("java.home") + File.separator + "bin" + File.separator + "java";
}

11

以下代码通过使用当前ProcessHandleProcessHandle.Info获取到当前java可执行文件的路径。

由于操作系统权限可能限制对命令信息的访问,所以结果被封装在Optional中。

String javaExecutablePath = ProcessHandle.current()
    .info()
    .command()
    .orElseThrow();

Java 9中新增了ProcessHandle,如果有人想知道的话。 :) - Bombe
这个在install4j或者exe4j中不起作用,可能在嵌入式环境中也是如此。 - Groostav
它在嵌入式环境中运行,意味着操作系统生成的可执行文件将被返回。它不一定像java那样运行 - 就像我在一个jpackaged应用程序中看到的那样。 - Queeg

2
这篇文章讨论了多个平台下寻找当前可执行文件路径的问题,非常有趣: Finding current executable's path without /proc/self/exe 根据这篇讨论,如果你真的需要,可以编写一些JNI包装器,使用#ifdef来区分当前平台并进行适当的本地调用。
如果你只在Linux上运行,则'/proc/self/exe'是指向实际运行的可执行文件的符号链接。 这有一个优点,即不依赖于任何环境变量(例如PATH或JAVA_HOME)。 但正如我所说,它绝对不是跨平台的。

0

是的,有一种方法可以获取JVM可执行文件的路径(如果存在)。将其包含在应用程序的配置中。有很多方法可以做到这一点:命令行参数--java myApp.Main /path/to/Java;属性--java -Dpath.to.java=/path/to/java等。

如果您想要真正的平台独立性,那么您的整个方案就有缺陷,因为不能保证JVM可执行文件的存在。我可以想象一个不需要java可执行文件的JVM。

如果您想要99.99%的平台独立性,那么我认为您已经拥有了所需的工具。


6
这并没有回答我的问题。我想知道如何在运行时确定JVM可执行文件的位置,而不是在启动JVM之前预先确定。你假设我控制JVM的调用方式,但事实并非如此。 - Samad Lotia
OP想要在程序内部确定JVM的可执行文件。这意味着(a)确保了JVM可执行文件的存在(尽管它可能不在文件系统中,但如果这是可能的,问题就会提到),(b)此答案对程序的命令行参数施加了限制,并要求将此数据穿过应用程序直到需要它的地方,这意味着这是最后的备选方案,以防其他方法都无法奏效。 - toolforger

-4

你正在尝试分叉整个JVM。

  1. 这是极其低效的,主要是因为另一个Java进程的重量。如果你经常这样做,那么你的程序将会非常慢。
  2. 线程存在的原因就是为了解决这个问题。

但是如果你真的必须这样做,可以尝试直接执行java -arguments,因为大多数标准的Java安装都将Java放在cli路径上。


这个问题并没有提到启动,所以你应该说“如果你正在使用java.exe进行启动,请注意...”。这个问题只是关于获取正在运行的java exe。 - Paul Jowett
1
除了jowierun所写的内容外,分叉JVM也有好处:
  1. JVM之间没有类加载冲突——这对于大型应用程序非常重要。
  2. 运行昂贵算法时,将其作为单独的进程运行是个好主意;它可以避免内存限制。
- Samad Lotia
我需要Java路径,以便将其传递给Python子进程,该进程可能需要使用需要有效Java路径的库...有点奇怪和丑陋,但是在这种情况下,您实际上需要知道Java VM内部的java.exe路径。 - DGoiko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接