¿Cómo puedo detectar qué tipo de JRE está instalado? 32 bits frente a 64 bits

Durante la instalación con un instalador NSIS, necesito verificar qué JRE (32 bits frente a 64 bits) está instalado en un sistema. Ya sé que puedo verificar la propiedad del sistema ” sun.arch.data.model “, pero esto es específico de Sun. Me pregunto si hay una solución estándar para esto.

La architecture JVM en uso se puede recuperar utilizando la propiedad ” os.arch “:

 System.getProperty("os.arch"); 

La parte “os” parece ser un nombre poco apropiado, o quizás los diseñadores originales no esperaban que las JVM se ejecutaran en architectures para las que no estaban escritas. Los valores de retorno parecen ser inconsistentes .

El equipo de instalación de NetBeans está abordando el problema de la architecture JVM vs OS. Citar:

x64 bit: Java y Sistema

Rastreado como el Issue 143434 .

Actualmente usamos x64 bit de JVM para determinar si el sistema (y por lo tanto Platform.getHardwareArch ()) es de 64 bits o no. Esto definitivamente es incorrecto ya que es posible ejecutar JVM de 32 bits en un sistema de 64 bits. Deberíamos encontrar una solución para verificar el OS real de 64 bits en caso de ejecutarse en una JVM de 32 bits.

  • para Windows se puede hacer usando WindowsRegistry.IsWow64Process ()
  • para Linux – marcando ‘uname -m / -p’ == x86_64
  • para Solaris se puede hacer utilizando, por ejemplo, ‘isainfo -b’
  • para Mac OSX no se puede hacer usando argumentos de uname, probablemente se puede resolver creando un binario de 64 bits y ejecutándolo en la plataforma … (desafortunadamente, esto no funciona 🙁 He creado solo binarios con x86_64 y el arco ppc64 y se ejecutó con éxito en Tiger ..)
  • para compatibilidad con Unix genérico, tampoco está claro … probablemente buscando la misma ‘uname -m / -p’ / ‘getconf LONG_BIT’ y comparándola con algunos valores posibles de 64 bits (x86_64, x64, amd64, ia64 )

Propiedades de ejemplo de diferentes JVM que se ejecutan en 64 bits 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 

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

(La versión de GNU no informa la propiedad “sun.arch.data.model”, presumiblemente otras JVM tampoco).

Estoy usando NSIS y Launch4j para envolver una aplicación Java Desktop. Así que no solo necesito detectar cualquier JRE, sino también el que Launch4j encontrará con su algoritmo de búsqueda. El único enfoque que tiene sentido es ejecutar un progtwig corto de Java dentro del instalador de NSIS. Aquí está el Java:


     clase pública DetectJVM {
         claves de cadena privadas estáticas privadas [] = {
             "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]);
             para (Tecla de cadena: teclas) {
                 Propiedad String = System.getProperty (clave);
                 if (print) System.out.println (key + "=" + propiedad);
                 if (property! = null) {
                     int errCode = (property.indexOf ("64")> = 0)?  64: 32;
                     if (print) System.out.println ("err code =" + errCode);
                     System.exit (errCode);
                 }
             }
         }
     }

Envuelve esto con Launch4J. Use el tipo de encabezado GUI pero también configurado en verdadero. De lo contrario, el código de error se perderá. (Puse todo esto en mi script de comstackción Netbeans Ant.

Aquí está el código NSIS que lo usa:


 Archivo ... ;  desempaquetar archivos incluyendo detectjvm.exe.
 ClearErrors
 ExecWait '"$ INSTDIR \ detectjvm.exe"' $ 0
 IfErrors DetectExecError
 IntCmp $ 0 0 DetectError DetectError DoneDetect
 DetectExecError:
     StrCpy $ 0 "error de ejecución"
 DetectError:
     MessageBox MB_OK "No se pudo determinar la architecture de JVM ($ 0). Suponiendo 32 bits."
     Goto NotX64
 DoneDetect:
 IntCmp $ 0 64 X64 NotX64 NotX64
 X64:
     Archivo ... DLL AMD de 64 bits.
     Goto DoneX64
 NotX64:
     Archivo ... DLL x86 de 32 bits.
 DoneX64:
 Eliminar $ INSTDIR \ detectjvm.exe

Esto ha funcionado bien en una gran variedad de máquinas de WinXP sin SP a través de Vista y Win7 con todos los SP, 32 y 64 bits.

Tenga en cuenta que en mi secuencia de comandos NSIS estoy usando un paquete existente que comprueba si la JVM está instalada y lo hace primero, por lo que la selección predeterminada de 32 bits solo ocurrirá si algo salió mal con la instalación de JVM, en cuyo caso el conjunto de archivos DLL que copia no importará de todos modos.

Espero que esto sea útil para alguien.

Al escribir código Java, ¿cómo distingo entre operación de 32 y 64 bits?

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

No hay una API pública que le permita distinguir entre la operación de 32 y 64 bits. Piense en 64 bits como una plataforma más en la carrera de escribir una vez, ejecutar en cualquier lugar. Sin embargo, si desea escribir un código que sea específico de la plataforma (la culpa es suya), la propiedad del sistema sun.arch.data.model tiene el valor “32”, “64” o “desconocido”.

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

En Linux, my (java) vm informa java.vm.name = Java HotSpot (TM) 64-Bit Server VM. Los javadocs para System declaran que System.getProperty siempre tendrá un valor para esto, pero que son silenciosos en sun.arch.data.model.

Lamentablemente, no especifican cuál será la propiedad del sistema, por lo que algunas otras JVM podrían informar java.vm.name = Edgar.

Por cierto, por “instalado en el sistema”, supongo que te refieres a “la JVM actual corriendo”?

Puede haber JVM de 32 bits y de 64 bits disponibles en el sistema, y ​​muchos de ellos.

Si ya tiene dll’s para cada plataforma compatible, considere crear un pequeño archivo ejecutable que se vincule y ejecute para que pueda probar si la plataforma admite una funcionalidad determinada. Si se ejecutan los enlaces ejecutables, puede instalar las bibliotecas compartidas correspondientes.

Si tiene la ruta al .exe que desea verificar, puede usar esta respuesta . Básicamente solo mira los encabezados en el archivo .exe y le dice si es 64 o 32 bits en Windows.

 java -version 

Para una versión Java de 64 bits, imprimirá:

 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) 

Por 32 bits será solo

 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) 

El siguiente código verifica el campo machineType en cualquier ejecutable de Windows para determinar si es de 32 o 64 bits:

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

Tenga en cuenta que el código ha sido compactado por brevedad ...