Comment est-ce que je détecte quel type de JRE est installé – 32bit vs. 64bit

Lors de l’installation avec un installateur NSIS, je dois vérifier quel JRE (32 bits vs 64 bits) est installé sur un système. Je sais déjà que je peux vérifier une propriété système ” sun.arch.data.model “, mais celle-ci est spécifique à Sun. Je me demande s’il existe une solution standard pour cela.

L’architecture JVM utilisée peut être récupérée en utilisant la propriété ” os.arch “:

 System.getProperty("os.arch"); 

La partie “os” semble être un peu trompeuse, ou peut-être que les concepteurs originaux ne s’attendaient pas à ce que les JVM soient exécutées sur des architectures pour lesquelles ils n’avaient pas été écrits. Les valeurs de retour semblent être incohérentes .

L’équipe NetBeans Installer s’attaque au problème de l’architecture JVM vs OS. Citation:

bit x64: Java et système

Suivi sous le numéro 143434 .

Actuellement, nous utilisons un bit x64 de JVM pour déterminer si le système (et donc Platform.getHardwareArch ()) est 64 bits ou non. Cela est certainement faux car il est possible d’exécuter une JVM 32 bits sur un système 64 bits. Nous devrions trouver une solution pour vérifier le système d’exploitation réel 64 bits en cas d’exécution sur une machine virtuelle Java 32 bits.

  • pour Windows, cela peut être fait en utilisant WindowsRegistry.IsWow64Process ()
  • pour Linux – en cochant ‘uname -m / -p’ == x86_64
  • pour Solaris, cela peut être fait en utilisant par exemple ‘isainfo -b’
  • pour Mac OSX, cela ne peut pas être fait en utilisant des arguments Uname, probablement en créant un fichier binary 64 bits et en l’exécutant sur la plate-forme … (malheureusement, cela ne fonctionne pas 🙁 J’ai créé binary uniquement avec x86_64 et ppc64 arch et il a été exécuté avec succès sur Tiger ..)
  • pour le support générique d’Unix – ce n’est pas clair aussi… vérifiant probablement le même ‘uname -m / -p’ / ‘getconf LONG_BIT’ et le comparant avec quelques valeurs possibles de 64 bits (x86_64, x64, amd64, ia64 ).

Exemples de propriétés de différentes JVM fonctionnant sur Ubuntu 8.0.4 64 bits:

32 bits 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 bits 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 bits 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 version GNU ne rapporte pas la propriété “sun.arch.data.model”, sans doute pas les autres JVM non plus.)

J’utilise NSIS et Launch4j pour emballer une application Java Desktop. Je n’ai donc pas seulement besoin de détecter un JRE, mais celui que Launch4j trouvera avec son algorithme de recherche. La seule approche sensée consiste à exécuter un programme Java court dans le programme d’installation de NSIS. Voici le Java:


     classe publique DetectJVM {
         clés de chaîne statiques finales privées [] = {
             "sun.arch.data.model",
             "com.ibm.vm.bitmode",
             "os.arch",
         };
         main statique vide statique (Ssortingng [] args) {
             boolean print = args.length> 0 && "-print" .equals (args [0]);
             pour (clé de chaîne: clés) {
                 Ssortingng property = System.getProperty (clé);
                 if (print) System.out.println (clé + "=" + propriété);
                 if (propriété! = null) {
                     int errCode = (property.indexOf ("64")> = 0)?  64: 32;
                     if (print) System.out.println ("err code =" + errCode);
                     System.exit (errCode);
                 }
             }
         }
     }

Emballez ceci avec Launch4J. Utilisez le type d’en-tête de l’interface graphique, mais définissez-le également sur true. Sinon, le code d’erreur sera perdu. (Je mets tout cela dans mon script de compilation Netbeans Ant.

Voici le code NSIS correspondant qui l’utilise:


 Fichier ... ;  décompresser les fichiers, y compris detectjvm.exe.
 ClearErrors
 ExecWait '"$ INSTDIR \ detectjvm.exe"' $ 0
 IfErrors DetectExecError
 IntCmp $ 0 0 DetectError DetectError DoneDetect
 DetectExecError:
     StrCpy $ 0 "erreur d'exécution"
 DetectError:
     MessageBox MB_OK "Impossible de déterminer l'architecture JVM ($ 0). En supposant que 32 bits."
     Aller à NotX64
 DoneDetect:
 IntCmp $ 0 64 X64 NotX64 NotX64
 X64:
     Fichier ... DLL AMD 64 bits.
     Aller à DoneX64
 NotX64:
     Fichier ... 32 bits x86 DLL.
 DoneX64:
 Supprimer $ INSTDIR \ detectjvm.exe

Cela a bien fonctionné sur une très grande variété de machines à partir de WinXP sans SP via Vista et Win7 avec tous les SP, 32 et 64 bits.

Notez que dans mon script NSIS, j’utilise un package existant qui vérifie si la JVM est installée et le fait en premier. La sélection 32 bits par défaut ne se produit que si quelque chose ne va pas avec l’installation de la JVM. Le jeu de DLL que vous copiez n’a pas d’importance de toute façon.

J’espère que cela est utile à quelqu’un.

Lors de l’écriture du code Java, comment faire la distinction entre les opérations 32 et 64 bits?

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

Il n’y a pas d’API publique permettant de distinguer les opérations 32 et 64 bits. Pensez à la version 64 bits comme à une autre plate-forme dans la tradition write once, run everywhere. Cependant, si vous souhaitez écrire du code spécifique à la plate-forme (dommage pour vous), la propriété système sun.arch.data.model a la valeur “32”, “64” ou “unknown”.

 import sun.misc.*; import java.lang.reflect.*; public class UnsafeTest { public static void main(Ssortingng[] args) throws NoSuchFieldException, IllegalAccessException { Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); unsafeField.setAccessible(true); Unsafe unsafe = (Unsafe) unsafeField.get(null); System.out.println(unsafe.addressSize()); } } 

Sous linux, ma (java) vm rapporte java.vm.name = VM serveur Java HotSpot (64 bits). Les javadocs pour System déclarent que System.getProperty aura toujours une valeur pour cela, mais sont silencieux sur sun.arch.data.model.

Malheureusement, ils ne spécifient pas la propriété du système, de sorte que d’autres machines JVM pourraient simplement signaler java.vm.name = Edgar.

BTW, par “installé sur le système”, je suppose que vous voulez dire “la JVM en cours d’exécution”?

Il pourrait y avoir des JVM 32 bits et 64 bits disponibles sur le système, et beaucoup d’entre elles.

Si vous avez déjà des DLL pour chaque plate-forme prise en charge, envisagez de créer un petit exécutable qui lie et s’exécute de manière à pouvoir tester si la plate-forme prend en charge une fonctionnalité donnée. Si l’exécutable lie et s’exécute, vous pouvez installer les bibliothèques partagées correspondantes.

Si vous avez le chemin d’access au fichier .exe que vous souhaitez vérifier, vous pouvez utiliser cette réponse . Fondamentalement, il ne fait que regarder les en-têtes dans le fichier .exe et vous indique s’il est 64 ou 32 bits sous Windows.

 java -version 

Pour une version Java 64 bits, elle sera imprimée:

 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) 

Pour 32 bits ce sera juste

 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) 

Le code suivant vérifie le champ machineType dans tout exécutable Windows pour déterminer s’il est 32 ou 64 bits:

 public class ExeDetect { public static void main(Ssortingng[] 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; } } 

Notez que le code a été compacté pour plus de brièveté ...