【问题标题】:How do I detect which kind of JRE is installed -- 32bit vs. 64bit如何检测安装了哪种 JRE——32 位与 64 位
【发布时间】:2010-10-22 21:04:09
【问题描述】:

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

【问题讨论】:

    标签: 64-bit 32-bit nsis java


    【解决方案1】:

    可以使用“os.arch”属性检索正在使用的 JVM 架构:

    System.getProperty("os.arch");
    

    “os”部分似乎有点用词不当,或者可能最初的设计者并没有期望 JVM 可以在他们不是为之编写的架构上运行。返回值似乎是inconsistent

    NetBeans 安装程序团队是 JVM 与 OS 架构的tackling the issue。引用:

    x64 位:Java 和系统

    跟踪为Issue 143434

    目前我们使用 x64 位的 JVM 来 确定系统是否(因此 Platform.getHardwareArch()) 是 64 位的 或不。这绝对是错误的,因为 可以运行 32 位 JVM 64位系统。我们应该找到一个 检查 OS 真正 64 位的解决方案 如果在 32 位 JVM 上运行。

    • 对于 Windows,可以使用 WindowsRegistry.IsWow64Process() 来完成
    • 对于 Linux - 通过检查 'uname -m/-p' == x86_64
    • 对于 Solaris,可以使用例如'isainfo -b'
    • 对于 Mac OSX,它不能使用 uname 参数来完成,可能它可以 通过创建 64 位二进制文​​件解决 并在平台上执行... (不幸的是,这不起作用:( 我只用 x86_64 创建了二进制文件 和 ppc64 拱,它是成功的 在老虎身上处决……)
    • 对于通用 Unix 支持 - 也不清楚...可能正在检查 对于相同的 'uname -m/-p' / 'getconf LONG_BIT' 并将其与一些比较 可能的 64 位值(x86_64、x64、 amd64, ia64)。

    来自不同 JVM 的示例属性,均在 64 位 Ubuntu 8.0.4 上运行:

    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 也不报告。)

    【讨论】:

      【解决方案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)
      

      【讨论】:

      • 你可以在命令行试试:java -d64 -version 如果不是64位版本,你会得到类似这样的信息:This Java instance does not support a 64-bit JVM。请安装所需的版本。有关更多信息,请参阅 JVM 的帮助选项 java -help
      【解决方案3】:

      如果您有要检查的 .exe 的路径,可以使用this answer。基本上它只是查看 .exe 文件中的标头并告诉您它在 Windows 上是 64 位还是 32 位。

      【讨论】:

        【解决方案4】:

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

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

        没有可让您区分 32 和 64 位操作。将 64 位视为 一次编写,随处运行的传统。但是,如果你想写 特定于平台的代码(您感到羞耻),系统属性 sun.arch.data.model 的值为“32”、“64”或“未知”。

        【讨论】:

        • 正如 Thorbjørn Ravn Andersen 在另一篇文章中所说,32 位 JVM 在 64 位操作系统上运行良好。如果您担心 JVM 位宽而不是操作系统位宽,请使用 sun.arch.data.model 属性(假设您在 Hot Spot JVM 上运行...)
        • 位问题不是因为 java 代码本身,而是因为我们的软件附带的包装器。假设如下: 如果客户尝试安装我们的 64Bit SW 版本,但他只安装了 32Bit Java;他必须被告知......
        【解决方案5】:

        以下代码检查任何 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;
          }
        }
        

        请注意,为简洁起见,代码已被压缩...

        【讨论】:

        • 请注意,只要用户不使用相同的 jre 版本,代码就会中断...
        • 这是在 Windows 上检测 64 位可执行文件的通用方法。没有特定于 jre 版本的内容。
        • 如果您更改为 "C:\Program Files\Java\jre6\,..."!"C:\Program Files (x86)\Java\jre6\,..." 那么它是稍微好一点,但只能在 Windows 平台和常规安装上使用。
        • @PeterSmith 这取决于 JRE 版本,因为您使用的硬编码路径仅在特定 JRE 版本安装在默认目录中时才存在。您是否以其他方式在未显示的代码中以任何形式将其抽象出来?
        【解决方案6】:

        我正在使用 NSIS 和 Launch4j 来包装 Java 桌面应用程序。因此,我不仅需要检测任何 JRE,还需要使用 Launch4j 的搜索算法找到的那个。唯一有意义的方法是在 NSIS 安装程序中运行一个简短的 Java 程序。这是Java:

        公共类检测JVM { 私有静态最终字符串键 [] = { "sun.arch.data.model", "com.ibm.vm.bitmode", "os.arch", }; 公共静态无效主要(字符串[]参数){ 布尔打印 = args.length > 0 && "-print".equals(args[0]); 对于(字符串键:键){ 字符串属性 = System.getProperty(key); if (print) System.out.println(key + "=" + property); 如果(属性!= null){ int errCode = (property.indexOf("64") >= 0) ? 64:32; if (print) System.out.println("err code=" + errCode); System.exit(errCode); } } } }

        用 Launch4J 包装它。使用 GUI 标头类型但也设置为 true。否则错误代码将丢失。 (我将所有这些都放在了我的 Netbeans Ant 构建脚本中。

        这是使用它的匹配 NSIS 代码:

        文件 ... ;解压文件,包括detectjvm.exe。 清除错误 ExecWait '"$INSTDIR\detectjvm.exe"' $0 IfErrors DetectExecError IntCmp $0 0 DetectError DetectError DoneDetect 检测执行错误: StrCpy $0“执行错误” 检测错误: MessageBox MB_OK “无法确定 JVM 架构 ($0)。假设为 32 位。” 转到 NotX64 完成检测: IntCmp $0 64 X64 NotX64 NotX64 X64: 文件 ... 64 位 AMD DLL。 转到完成X64 非X64: 文件 ... 32 位 x86 DLL。 完成X64: 删除 $INSTDIR\detectjvm.exe

        这在从没有 SP 的 WinXP 到 Vista 和具有所有 SP、32 位和 64 位的 Win7 的各种机器上运行良好。

        请注意,在我的 NSIS 脚本中,我使用了一个现有的包来检查 JVM 是否已安装并首先执行此操作,因此只有在 JVM 安装出现严重错误时才会出现默认的 32 位选择,在这种情况下,您复制的 DLL 集无论如何都无关紧要。

        希望这对某人有帮助。

        【讨论】:

        • 这是一个非常有用的解决方法。问题是,如果用户的 64 位机器没有安装 JVM 怎么办?然后脚本会做出错误的假设。
        • 请注意,对于我的情况,我需要使用 Launch4J 进入控制台。
        • 这对于像S390x这样的奇怪架构可能会失败。
        • 我应该说我的应用程序仅适用于 mac 和 window。
        【解决方案7】:
        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());
          }
        }
        

        【讨论】:

          【解决方案8】:

          系统上可能同时存在 32 位和 64 位 JVM,而且数量很多。

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

          【讨论】:

            【解决方案9】:

            在 linux 上,我的 (java) vm 报告 java.vm.name=Java HotSpot(TM) 64 位服务器 VM。 System 的 javadocs 声明 System.getProperty 将始终为此设置一个值,但对 sun.arch.data.model 保持沉默。

            不幸的是,他们没有指定系统属性是什么,因此其他一些 JVM 可能只会报告 java.vm.name=Edgar。

            顺便说一句,“安装在系统上”,我假设您的意思是“当前运行的 JVM”?

            【讨论】:

              猜你喜欢
              • 2013-06-21
              • 1970-01-01
              • 2011-04-24
              • 1970-01-01
              • 2017-08-26
              • 2020-05-28
              • 1970-01-01
              • 2018-03-04
              相关资源
              最近更新 更多