如何检测已安装的JRE是32位还是64位?

51

在使用NSIS安装程序进行安装时,我需要检查系统上安装了哪个JRE(32位还是64位)。我已经知道可以检查系统属性“sun.arch.data.model”,但这只适用于Sun。我想知道是否有标准解决方案。

9个回答

50

可以使用 "os.arch" 属性来获取正在使用的JVM架构:

System.getProperty("os.arch");

"os"这部分似乎有些误导,或者最初的设计者没有预料到JVM会在它们未编写的架构上运行。返回值似乎不一致

NetBeans安装程序团队正在解决JVM与操作系统架构之间的问题。引用:

被标记为问题143434
目前,我们使用JVM的x64位来确定系统(因此Platform.getHardwareArch())是否为64位。这绝对是错误的,因为在64位系统上可以运行32位JVM。如果在32位JVM上运行,则应找到解决方案以检查操作系统的真实64位性。
  • 对于Windows,可以使用WindowsRegistry.IsWow64Process()。
  • 对于Linux-通过检查'uname -m / -p' == x86_64
  • 对于Solaris,可以使用例如'isainfo -b'
  • 对于Mac OSX,无法使用uname参数完成,可能可以通过创建64位二进制文件并在平台上执行来解决...(不幸的是,这不起作用:(我只创建了带有x86_64和ppc64架构的二进制文件,并且它已成功在Tiger上执行。)
  • 对于通用Unix支持-也不清楚...可能检查相同的'uname -m / -p'/'getconf LONG_BIT'并将其与一些可能的64位值(x86_64、x64、amd64、ia64)进行比较。

  • 以下是在运行于64位Ubuntu 8.0.4的不同JVM中的样本属性:

    32位IBM 1.5:

    java.vendor=IBM Corporation
    java.vendor.url=http://www.ibm.com/
    java.version=1.5.0
    java.vm.info=J2RE 1.5.0 IBM J9 2.3 Linux x86-32 j9vmxi3223-20061001 (JIT enabled)
    J9VM - 20060915_08260_lHdSMR
    JIT  - 20060908_1811_r8
    GC   - 20060906_AA
    java.vm.name=IBM J9 VM
    java.vm.specification.name=Java Virtual Machine Specification
    java.vm.specification.vendor=Sun Microsystems Inc.
    java.vm.specification.version=1.0
    java.vm.vendor=IBM Corporation
    java.vm.version=2.3
    os.arch=x86
    os.name=Linux
    os.version=2.6.24-23-generic
    sun.arch.data.model=32
    

    64位 Sun 1.6:

    java.vendor=Sun Microsystems Inc.
    java.vendor.url=http://java.sun.com/
    java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi
    java.version=1.6.0_05
    java.vm.info=mixed mode
    java.vm.name=Java HotSpot(TM) 64-Bit Server VM
    java.vm.specification.name=Java Virtual Machine Specification
    java.vm.specification.vendor=Sun Microsystems Inc.
    java.vm.specification.version=1.0
    java.vm.vendor=Sun Microsystems Inc.
    java.vm.version=10.0-b19
    os.arch=amd64
    os.name=Linux
    os.version=2.6.24-23-generic
    sun.arch.data.model=64
    

    64位GNU 1.5:

    java.vendor=Free Software Foundation, Inc.
    java.vendor.url=http://gcc.gnu.org/java/
    java.version=1.5.0
    java.vm.info=GNU libgcj 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
    java.vm.name=GNU libgcj
    java.vm.specification.name=Java(tm) Virtual Machine Specification
    java.vm.specification.vendor=Sun Microsystems Inc.
    java.vm.specification.version=1.0
    java.vm.vendor=Free Software Foundation, Inc.
    java.vm.version=4.2.4 (Ubuntu 4.2.4-1ubuntu3)
    os.arch=x86_64
    os.name=Linux
    os.version=2.6.24-23-generic
    

    (GNU版本不报告“sun.arch.data.model”属性;其他JVM可能也不会报告。)

    7
    我正在使用NSIS和Launch4j来包装一个Java桌面应用程序。因此,我不仅需要检测任何JRE,还需要使用Launch4j的搜索算法找到的JRE。唯一有意义的方法是在NSIS安装程序中运行一个短的Java程序。以下是Java代码:
    ``` public class DetectJVM { private static final String keys [] = { "sun.arch.data.model", "com.ibm.vm.bitmode", "os.arch", }; public static void main (String [] args) { boolean print = args.length > 0 && "-print".equals(args[0]); for (String key : keys ) { String property = System.getProperty(key); if (print) System.out.println(key + "=" + property); if (property != null) { int errCode = (property.indexOf("64") >= 0) ? 64 : 32; if (print) System.out.println("err code=" + errCode); System.exit(errCode); } } } } ```
    将其与Launch4J一起使用。使用GUI标题类型,但也将set设置为true。否则,错误代码将会丢失。(我把所有这些放在我的Netbeans Ant构建脚本中)
    以下是相应的NSIS代码:
    ``` File ... ; 解压文件,其中包括detectjvm.exe。 ClearErrors ExecWait '"$INSTDIR\detectjvm.exe"' $0 IfErrors DetectExecError IntCmp $0 0 DetectError DetectError DoneDetect DetectExecError: StrCpy $0 "exec error" DetectError: MessageBox MB_OK "Could not determine JVM architecture ($0). Assuming 32-bit." Goto NotX64 DoneDetect: IntCmp $0 64 X64 NotX64 NotX64 X64: File ... 64位AMD DLL。 Goto DoneX64 NotX64: File ... 32位x86 DLL。 DoneX64: Delete $INSTDIR\detectjvm.exe ```
    这在各种机器上都运行良好,从没有服务包的WinXP到带有所有服务包的Vista和Win7,32位和64位。
    请注意,在我的NSIS脚本中,我使用现有的软件包来检查JVM是否已安装并首先执行该操作,因此默认的32位选择仅在JVM安装出现问题时才会发生,此时您复制的DLL集合无论如何都不重要。
    希望这对某些人有所帮助。

    这是一个非常有用的解决方法。问题是,如果用户的64位机器没有安装JVM呢?脚本将会做出错误的假设。 - Cheok Yan Cheng
    请注意,对于我的情况,我需要使用Launch4J将其制作为控制台应用程序。 - Cheok Yan Cheng
    这可能会在某些奇怪的架构(如S390x)上失败。 - tresf
    我应该说我的应用程序只适用于Mac和Windows。 - Gene

    4

    当编写Java代码时,我如何区分32位和64位操作?

    http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#64bit_detection

    没有公共API可以区分32位和64位操作。将64位视为在“编写一次,到处运行”的传统中的另一个平台。但是,如果您想编写特定于平台的代码(真可耻),系统属性sun.arch.data.model具有值“32”、“64”或“unknown”。


    正如Thorbjørn Ravn Andersen在另一篇帖子中所说,32位JVM可以在64位操作系统上运行良好。如果您担心JVM位宽而不是操作系统位宽(假设您正在运行Hot Spot JVM...),请使用sun.arch.data.model属性。 - billsimons
    1
    位问题并不是由于Java代码本身,而是由于我们软件附带的包装器引起的。假设以下情况:如果客户尝试安装我们的64位软件版本,但他只安装了32位Java,则必须通知他... - user97629

    2
    java -version
    

    对于64位Java版本,它将打印:
    java version "1.8.0_92"
    Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
    Java HotSpot(TM) ***64-Bit*** Server VM (build 25.92-b14, mixed mode)
    

    对于32位系统,只需执行以下操作:

    java version "1.8.0_92"
    Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
    Java HotSpot(TM) Client VM (build 25.92-b14, mixed mode)
    

    1
    您可以在命令行上尝试以下内容: java -d64 -version 如果不是64位版本,您将收到以下类似消息: 此Java实例不支持64位JVM。请安装所需版本。 有关更多信息,请查阅JVM的帮助选项 java -help - Massimo

    2
    import sun.misc.*;
    
    import java.lang.reflect.*;
    
    public class UnsafeTest {
      public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        System.out.println(unsafe.addressSize());
      }
    }
    

    0
    在Linux上,我的(Java)虚拟机报告java.vm.name=Java HotSpot(TM) 64-Bit Server VM。System的javadocs声明System.getProperty将始终具有此值,但对sun.arch.data.model保持沉默。
    不幸的是,它们没有指定系统属性将是什么,因此其他某些JVM可能只报告java.vm.name=Edgar。
    顺便说一下,“安装在系统上”,我假设您指的是“当前运行的JVM”?

    0

    系统上可能有32位和64位的JVM可用,而且数量很多。

    如果您已经为每个支持的平台准备了dll,请考虑制作一个小型可执行文件来链接和运行,以便测试平台是否支持给定的功能。如果可执行文件链接并运行,则可以安装相应的共享库。


    -1

    如果你有想要检查的.exe文件路径,可以使用这个答案。基本上它只是查看.exe文件中的标头,告诉你它在Windows上是64位还是32位。


    -6
    以下代码检查任何Windows可执行文件中的machineType字段,以确定它是32位还是64位:
    public class ExeDetect
    {
      public static void main(String[] args) throws Exception {
        File x64 = new File("C:/Program Files/Java/jre1.6.0_04/bin/java.exe");
        File x86 = new File("C:/Program Files (x86)/Java/jre1.6.0/bin/java.exe");
        System.out.println(is64Bit(x64));
        System.out.println(is64Bit(x86));
      }
    
      public static boolean is64Bit(File exe) throws IOException {
        InputStream is = new FileInputStream(exe);
        int magic = is.read() | is.read() << 8;
        if(magic != 0x5A4D) 
            throw new IOException("Invalid Exe");
        for(int i = 0; i < 58; i++) is.read(); // skip until pe offset
        int address = is.read() | is.read() << 8 | 
             is.read() << 16 | is.read() << 24;
        for(int i = 0; i < address - 60; i++) is.read(); // skip until pe header+4
        int machineType = is.read() | is.read() << 8;
        return machineType == 0x8664;
      }
    }
    

    请注意,代码已经被压缩以便简洁。

    1
    请注意,只要用户不使用完全相同的JRE版本,代码就会中断... - Gregory Pakosz
    1
    这是一种通用的方法,用于在Windows上检测64位可执行文件。与JRE版本无关。 - Peter Smith
    1
    如果你将“C:\Program Files\Java\jre6,…”改为“C:\Program Files (x86)\Java\jre6,…”,那么在Windows平台和正常安装中都会有一点好转。 - RealHowTo
    @PeterSmith 这取决于JRE版本,因为您正在使用硬编码路径,这些路径仅存在于特定JRE版本安装在默认目录中的情况下。除此之外,在未显示的代码中,您是否以任何形式将其抽象化? - BryKKan

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