Как определить, какой тип JRE установлен - 32 бит против 64 бит

Во время установки с помощью установщика NSIS мне нужно проверить, какая JRE (32 бит против 64 бит) установлена ​​в системе. Я уже знаю, что могу проверить системное свойство "sun.arch.data.model", но это зависит от Sun. Мне интересно, есть ли для этого стандартное решение.

Ответ 1

Используемую архитектуру JVM можно получить, используя свойство os.arch":

System.getProperty("os.arch");

Часть "os" кажется немного неправильной, или, возможно, оригинальные дизайнеры не ожидали, что JVM будут работать на архитектурах, для которых они не были написаны. Возвращаемые значения кажутся несогласованными.

Команда установщика NetBeans решение проблемы в архитектуре JVM и ОС. Цитата:

x64 бит: Java и система

Отслеживается как Проблема 143434.

В настоящее время мы используем x64 бит JVM для определить, система (и, следовательно, Platform.getHardwareArch()) - это 64-разрядный или нет. Это, безусловно, неверно, поскольку можно запустить 32-битную JVM на 64-битная система. Мы должны найти решение для проверки реальной 64-битности ОС в случае запуска на 32-битной JVM.

  • для Windows это можно сделать с помощью WindowsRegistry.IsWow64Process()
  • для Linux - путем проверки "uname -m/-p" == x86_64
  • для Solaris это можно сделать, используя, например, 'isainfo -b'
  • для Mac OSX это невозможно сделать с использованием аргументов uname, возможно, это может быть решена путем создания 64-битного двоичного кода и выполнение на платформе... (к сожалению, это не работает:( Я создал двоичный файл только с x86_64 и archc ppc64, и это было успешно выполненный на тигере..)
  • для поддержки Generic Unix - также неясно... вероятная проверка для того же "uname -m/-p" /'getconf LONG_BIT 'и сравнивая его с некоторыми возможные 64-битные значения (x86_64, x64, amd64, ia64).

Примеры свойств из разных JVM, запущенных на 64-битном Ubuntu 8.0.4:

32bit 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

64bit 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

Я использую NSIS и Launch4j для переноса приложения Java Desktop. Поэтому мне нужно не только обнаружить любую JRE, но и Launch4j найдет ее алгоритм поиска. Единственный подход, который имел смысл - запустить небольшую программу Java в установщике NSIS. Здесь 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, но также установите значение true. В противном случае код ошибки будет потерян. (Я положил все это в своих Netbeans Ant build script.

Здесь соответствующий код NSIS, который его использует:

File ... ; unpack files including 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-bit AMD DLLs.
    Goto DoneX64
NotX64:
    File ... 32-bit x86 DLLs.
DoneX64:
Delete $INSTDIR\detectjvm.exe

Это отлично работает на очень большом количестве машин от WinXP без SP до Vista и Win7 со всеми SP, 32- и 64-разрядными.

Обратите внимание, что в моем NSIS script я использую существующий пакет, который проверяет, установлена ​​ли JVM и делает это в первую очередь, поэтому 32-битный выбор по умолчанию будет иметь место только в том случае, если что-то пошло не так с JVM install, и в этом случае набор DLL, который вы копируете, не имеет значения.

Надеюсь, это поможет кому-то.

Ответ 3

При написании кода Java, как я могу различать 32 и 64-разрядную операцию?

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

Нет публичного API, который позволяет различать 32 и 64-разрядная работа. Подумайте о 64-битной, как о другой платформе в пишите один раз, бегите в любую традицию. Однако, если вы хотите написать код, который является специфичным для платформы (стыдно за вас), свойство системы sun.arch.data.model имеет значение "32", "64" или "неизвестно".

Ответ 4

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());
  }
}

Ответ 5

В linux my (java) vm сообщает java.vm.name = Java HotSpot (TM) 64-разрядную серверную VM. Javadocs for System заявляют, что System.getProperty всегда будет иметь значение для этого, но молчат на sun.arch.data.model.

К сожалению, они не указывают, что будет системным свойством, так что некоторые другие JVM могут просто сообщить java.vm.name = Edgar.

Кстати, "установленным в системе", я предполагаю, что вы имеете в виду "текущая работа JVM"?

Ответ 6

В системе могут быть как 32-битные, так и 64-разрядные JVM, и много их.

Если у вас уже есть dll для каждой поддерживаемой платформы, рассмотрите возможность создания небольшого исполняемого файла, который соединяется и запускается, чтобы вы могли проверить, поддерживает ли платформа определенную функциональность. Если исполняемые ссылки и запуск, вы можете установить соответствующие разделяемые библиотеки.

Ответ 7

Если у вас есть путь к .exe, который вы хотите проверить, вы можете использовать этот ответ. В основном он просто смотрит на заголовки в файле .exe и сообщает вам, является ли это 64 или 32 бит в Windows.

Ответ 8

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)

Ответ 9

Следующий код проверяет поле machineType в любом исполняемом файле Windows, чтобы определить, 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;
  }
}

Обратите внимание, что код был сжат для краткости...