Come posso individuare il tipo di JRE installato: 32 bit contro 64 bit

Durante l’installazione con un programma di installazione NSIS, devo verificare quale JRE (32 bit vs 64 bit) è installato su un sistema. So già che posso controllare una proprietà di sistema ” sun.arch.data.model “, ma questo è specifico per Sun. Mi chiedo se esiste una soluzione standard per questo.

L’architettura JVM in uso può essere recuperata utilizzando la proprietà ” os.arch “:

 System.getProperty("os.arch"); 

La parte “os” sembra essere un po ‘impropria, o forse i progettisti originali non si aspettavano che JVM girasse su architetture per cui non erano stati scritti. I valori di ritorno sembrano essere incoerenti .

Il team di NetBeans Installer sta affrontando il problema dell’architettura JVM vs OS. Citazione:

x64 bit: Java e System

Tracciato come il problema 143434 .

Attualmente utilizziamo x64 bit di JVM per determinare se il sistema (e quindi Platform.getHardwareArch ()) è a 64 bit o meno. Questo è decisamente sbagliato dal momento che è ansible eseguire JVM a 32 bit su sistemi a 64 bit. Dovremmo trovare una soluzione per controllare OS real 64-bitness in caso di esecuzione su JVM a 32 bit.

  • per Windows può essere fatto usando WindowsRegistry.IsWow64Process ()
  • per Linux – selezionando ‘uname -m / -p’ == x86_64
  • per Solaris può essere fatto usando eg ‘isainfo -b’
  • per Mac OSX non può essere fatto usando argomenti uname, probabilmente può essere risolto creando binari a 64 bit ed eseguendo sulla piattaforma … (sfortunatamente, questo non funziona 🙁 Ho creato solo binari con x86_64 e ppc64 arch ed è stato eseguito con successo su Tiger ..)
  • per supporto Unix generico – non è chiaro … probabilmente controllando lo stesso ‘uname -m / -p’ / ‘getconf LONG_BIT’ e confrontandolo con alcuni possibili valori a 64-bit (x86_64, x64, amd64, ia64 ).

Proprietà di esempio di JVM differenti tutte in esecuzione su Ubuntu 8.0.4 64bit:

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 

64 bit dom 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 versione GNU non riporta la proprietà “sun.arch.data.model”, presumibilmente nemmeno altre JVM).

Sto usando NSIS e Launch4j per racchiudere un’app per Java Desktop. Quindi non ho bisogno solo di rilevare JRE, ma quello che Launch4j troverà con il suo algoritmo di ricerca. L’unico approccio che ha avuto senso è quello di eseguire un breve programma Java all’interno dell’installer NSIS. Ecco il Java:

     class pubblica DetectJVM {
         String stringhe finali statiche private [] = {
             "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 (Chiave stringa: chiavi) {
                 String proprietà = System.getProperty (chiave);
                 se (stampa) System.out.println (chiave + "=" + proprietà);
                 if (proprietà! = null) {
                     int errCode = (property.indexOf ("64")> = 0)?  64: 32;
                     if (print) System.out.println ("err code =" + errCode);
                     System.exit (errCode);
                 }
             }
         }
     }

Avvolgi questo con Launch4J. Utilizzare il tipo di intestazione della GUI, ma anche impostato su true. Altrimenti il ​​codice di errore andrà perso. (Ho messo tutto questo nel mio script di costruzione Netbeans Ant.

Ecco il codice NSIS corrispondente che lo utilizza:

 File ... ;  decomprimere i file incluso detectjvm.exe.
 ClearErrors
 ExecWait '"$ INSTDIR \ detectjvm.exe"' $ 0
 IfErrors DetectExecError
 IntCmp $ 0 0 DetectError DetectError DoneDetect
 DetectExecError:
     StrCpy $ 0 "errore exec"
 DetectError:
     MessageBox MB_OK "Imansible determinare l'architettura JVM ($ 0). Supponendo 32 bit."
     Vai a NotX64
 DoneDetect:
 IntCmp $ 0 64 X64 NotX64 NotX64
 X64:
     File ... DLL AMD a 64 bit.
     Goto DoneX64
 NotX64:
     File ... DLL x86 a 32 bit.
 DoneX64:
 Elimina $ INSTDIR \ detectjvm.exe

Questo ha funzionato bene su una grande varietà di macchine da WinXP senza SP tramite Vista e Win7 con tutti gli SP, 32 e 64 bit.

Si noti che nel mio script NSIS sto usando un pacchetto esistente che controlla se JVM è installato e lo fa prima, quindi la selezione predefinita a 32 bit si verificherebbe solo se qualcosa andasse male con l’installazione di JVM, nel qual caso il set di DLL che copi non importa comunque.

Spero che questo sia utile a qualcuno.

Quando si scrive codice Java, come faccio a distinguere tra le operazioni a 32 e 64 bit?

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

Non ci sono API pubbliche che ti permettano di distinguere tra operazioni a 32 e 64 bit. Pensa a 64-bit come a un’altra piattaforma nella scrittura una volta, esegui qualsiasi tradizione. Tuttavia, se desideri scrivere codice che sia specifico della piattaforma (vergogna per te), la proprietà di sistema sun.arch.data.model ha il valore “32”, “64” o “sconosciuto”.

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

Su Linux, my (java) vm segnala java.vm.name = Java Server di server a 64 bit HotSpot (TM). I javadocs per System dichiarano che System.getProperty avrà sempre un valore per questo, ma sono silenti su sun.arch.data.model.

Sfortunatamente non specificano quale sarà la proprietà di sistema, quindi qualche altra JVM potrebbe semplicemente segnalare java.vm.name = Edgar.

A proposito, per “installato sul sistema”, presumo tu intenda “la JVM corrente in esecuzione”?

Ci potrebbero essere sia JVM a 32 bit che a 64 bit disponibili sul sistema, e molte di esse.

Se disponi già di dll per ogni piattaforma supportata, valuta la possibilità di creare un piccolo eseguibile che collega ed esegui in modo da poter verificare se la piattaforma supporta una determinata funzionalità. Se i collegamenti eseguibili ed eseguiti, è ansible installare le librerie condivise corrispondenti.

Se si ha il percorso per l’exe che si desidera controllare, è ansible utilizzare questa risposta . Fondamentalmente guarda solo le intestazioni nel file .exe e ti dice se è 64 o 32 bit su Windows.

 java -version 

Per una versione java a 64 bit verrà stampato:

 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) 

Per 32 bit sarà 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) 

Il seguente codice controlla il campo machineType in qualsiasi file eseguibile di Windows per determinare se è 32 o 64 bit:

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

Si noti che il codice è stato compattato per brevità ...