51

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

4

9 回答 9

50

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

System.getProperty("os.arch");

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

NetBeans 安装程序团队正在解决JVM 与 OS 体系结构的问题。引用:

x64 位:Java 和系统

跟踪为问题 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 arch 并在 Tiger 上成功执行..)
  • 对于通用 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 位太阳 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 也不报告。)

于 2009-04-30T18:12:17.937 回答
7

我正在使用 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 集都无关紧要。

希望这对某人有帮助。

于 2010-11-09T19:53:25.897 回答
4

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

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

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

于 2011-01-15T03:41:45.117 回答
1
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());
  }
}
于 2009-10-12T22:19:31.783 回答
1
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)
于 2016-05-24T14:06:23.817 回答
0

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

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

于 2009-04-30T22:03:30.690 回答
0

On linux, my (java) vm reports java.vm.name=Java HotSpot(TM) 64-Bit Server VM. The javadocs for System declare that System.getProperty will always have a value for this but are silent on sun.arch.data.model.

Unfortunately they don't specify what the system property will be so some other JVM might just report java.vm.name=Edgar.

BTW, by "installed on the system", I assume you mean "the current running JVM"?

于 2009-04-30T15:02:12.933 回答
-1

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

于 2016-02-15T20:16:01.313 回答
-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;
  }
}

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

于 2009-06-04T12:54:14.857 回答