2008-09-07 8 views
38

Il semble que tout ce que vous pouvez faire avec bytecode soit aussi simple et rapide que le code natif. En théorie, vous pouvez même conserver l'indépendance de la plate-forme et du langage en distribuant les programmes et les bibliothèques en bytecode, puis en compilant le code natif lors de l'installation, plutôt que de le mettre en JIT.Quels sont les avantages de bytecode par rapport au code natif?

Donc, en général, quand voulez-vous exécuter bytecode au lieu de natif?

Répondre

31

Hank Shiffman de SGI a dit (il y a longtemps, mais il est jusqu'à true):

Il existe trois avantages de Java en utilisant le code d'octets au lieu d'aller à le code natif du système:

  1. portabilité: Chaque type d'ordinateur a son instruction unique, set. Alors que certains processeurs incluent les instructions pour leurs prédécesseurs, il est généralement vrai qu'un programme qui s'exécute sur un type d'ordinateur ne fonctionnera sur aucun autre. Ajoutez dans les services fournis par le système d'exploitation , que chaque système décrit en sa propre façon unique, et vous avez un problème de compatibilité . En général, vous ne pouvez pas écrire et compiler un programme pour un type de système et l'exécuter sur tout autre autre sans beaucoup de travail.Java obtient autour de cette limitation en insérant sa machine virtuelle entre l'application et l'environnement réel (ordinateur + système d'exploitation). Si une application est compilé en code Java octet et que le code d'octet est interprété la même manière dans tous les environnements alors vous pouvez écrire un seul programme qui fonctionnera sur toutes les différentes plates-formes où Java est pris en charge. (C'est la théorie, de toute façon dans pratique il y a toujours des petites incompatibilités guettaient le programmeur..)

  2. Sécurité: L'une des vertus de Java est son intégration dans le Web. Chargez une page Web qui utilise Java dans votre navigateur et le code Java est automatiquement téléchargé et exécuté. Mais que faire si le code détruit les fichiers, que ce soit par la malveillance ou la négligence sur la partie du programmeur? Java empêche les applets téléchargés de faire quoi que ce soit de destructif en interdisant opérations potentiellement dangereuses. Avant d'autoriser le code à s'exécuter, l'examine pour tenter de contourner la sécurité . Il vérifie que les données sont utilisées de manière cohérente: le code manipule un élément de données sous la forme d'un entier à un moment, puis essaie de l'utiliser car un pointeur sera intercepté ultérieurement et empêché d'être exécuté. (Le langage Java ne permet pas pointeur arithmétique, donc vous ne pouvez pas écrire du code Java pour faire ce que nous venons de décrire. Cependant, il n'y a rien pour empêcher quelqu'un d'écrire le code octet destructive s'utilisant un hexadécimal éditeur ou même la construction d'un octet Java assembleur de code.) Il n'est généralement pas possible d'analyser le code machine d'un programme avant l'exécution et déterminer s'il fait quoi que ce soit mauvais. Des astuces comme l'écriture de code auto-modifiable signifient que les mauvaises opérations ne peuvent même pas exister avant plus tard. Mais le code octet Java a été conçu pour ce type de validation: il n'a pas les instructions un programmeur malveillant utiliserait pour cacher leur assaut.

  3. Taille: Dans le monde du microprocesseur RISC est généralement préférable sur CISC. Il est préférable d'avoir un petit jeu d'instructions et d'utiliser de nombreuses instructions rapides pour faire un travail que d'avoir de nombreuses opérations complexes mises en œuvre comme instructions simples. RISC dessins nécessitent moins de portes sur la puce à mettre en œuvre leurs instructions, permettant pour plus de place pour les pipelines et d'autres techniques pour rendre chaque instruction plus rapide. Dans un interprète, cependant, rien de tout cela n'a d'importance. Si vous voulez mettre en œuvre une seule instruction pour l'instruction switch avec une longueur variable en fonction du nombre de clauses case , il n'y a aucune raison de ne pas faire donc.En fait, une instruction complexe mis en est un avantage pour une langue Web: cela signifie que le même programme sera plus petit (moins instructions d'une plus grande complexité), ce qui signifie moins de temps pour transférer dans notre Speed- réseau limité.

Donc, lorsque l'on considère le code octet vs natif, tenez compte que les compromis que vous voulez faire entre la portabilité, la sécurité, la taille et la vitesse d'exécution. Si la vitesse est le seul facteur important, allez natif. Si l'un des autres est plus important, passez au bytecode.

J'ajouterai également que la maintenance d'une série de compilations ciblées sur l'OS et l'architecture de la même base de code pour chaque version peut devenir très fastidieuse. C'est une grande victoire d'utiliser le même bytecode Java sur plusieurs plates-formes et de le faire "juste fonctionner".

+4

4 ans plus tard ... Portabilité: les compilateurs qui produisent du code natif peuvent compiler entre eux, comme gc (le compilateur officiel [Go] (http://golang.org/)) qui le rend aussi simple. Sécurité: [Native Client] (https://developers.google.com/native-client/) exécute du code natif dans un sandbox, limitant ainsi ses autorisations. Taille: rarement un problème ces jours-ci, même pour les appareils mobiles. –

+2

@Zippoxer Qu'est-ce qui se passe avec les quatre ans? La compilation croisée est un concept très ancien. Mais vous devez toujours compiler le code pour chaque plate-forme séparément. La virtualisation n'est pas non plus un nouveau concept, mais la virtualisation du code écrit pour l'exécution native n'est pas la même chose que la virtualisation du code qui est spécifiquement conçu pour être exécuté dans un bac à sable. En ce qui concerne la taille, je n'appellerais pas du tout le code CISC Java du tout. La même chose vaut pour CIL. – Malcolm

2

Je pense que vous venez de répondre à votre propre question: l'indépendance de la plate-forme. Le bytecode indépendant de la plate-forme est produit et distribué sur sa plate-forme cible. Une fois exécuté, il est rapidement compilé en code natif avant le début de l'exécution, ou simultanément (Just In Time). La Java JVM et vraisemblablement les runtimes .NET fonctionnent selon ce principe. Bytecode crée un niveau d'indirection supplémentaire.

9

Les avantages de ce niveau supplémentaire d'indirection sont:

  • indépendance de la plate-forme
  • peut créer un certain nombre de langages de programmation (syntaxe) et ont de les compiler à la même bytecode.
  • x86, x64 et IA64 n'ont plus besoin d'être compilés en tant que binaires séparés. Seule la machine virtuelle appropriée doit être installée.
  • Chaque système d'exploitation doit simplement créer une machine virtuelle et prendre en charge le même programme.
  • La compilation juste à temps vous permet de mettre à jour un programme simplement en remplaçant un seul fichier source patché. (Très bénéfique pour les pages web)

Certains des inconvénients:

  • Performance
  • Plus facile à décompiler
1

Idéalement, vous auriez un bytecode portable qui compile Just In Time en code natif. Je pense que la raison pour laquelle les interpréteurs bytecode existent sans JIT est due principalement au fait pratique que la compilation de code natif ajoute de la complexité à une machine virtuelle. Il faut du temps pour construire, déboguer et maintenir ce composant supplémentaire. Tout le monde n'a pas le temps ou les ressources pour prendre cet engagement.

Un facteur secondaire est la sécurité. Il est beaucoup plus facile de vérifier qu'un interpréteur ne plante pas que de garantir la même chose pour le code natif.

La troisième est la performance. Il peut souvent prendre plus de temps pour générer le code machine que pour interpréter le bytecode pour les petits morceaux de code qui ne s'exécutent qu'une seule fois.

15

Les performances de pratiquement n'importe quel programme s'amélioreront si elles sont compilées, exécutées avec le profilage, et les résultats sont renvoyés dans le compilateur pour un second passage. Les chemins de code réellement utilisés seront optimisés de manière plus agressive, les boucles déroulées exactement au bon degré, et les chemins d'instructions chauds arrangés pour maximiser les coups de $.

Toutes les bonnes choses, mais il est presque jamais fait parce qu'il est ennuyeux de passer par tant d'étapes pour construire un binaire.

Ceci présente l'avantage d'exécuter le bytecode pendant un moment avant de le compiler en code natif: les informations de profilage sont automatiquement disponibles. Le résultat après la compilation Just-In-Time est un code natif hautement optimisé pour les données spécifiques que le programme est en train de traiter. Etre capable d'exécuter le bytecode permet également une optimisation native plus agressive qu'un compilateur statique peut utiliser en toute sécurité. Par exemple, si l'un des arguments d'une fonction est toujours noté NULL, toute la gestion de cet argument peut simplement être omise du code natif. Il y aura une brève vérification de validité des arguments dans la fonction prologue, si cet argument n'est pas NULL, la machine virtuelle abandonne le bytecode et recommence à profiler.

3

Toutes les bonnes réponses, mais mon hot-button a été atteint - performance. Si le code en cours d'exécution passe tout son temps à appeler la bibliothèque/les routines système - opérations de fichiers, opérations de base de données, envoi de messages Windows, peu importe s'il est JITté, car la plupart du temps est passé en attente pour les opérations de niveau inférieur à compléter.

Cependant, si le code contient des choses que nous passons généralement appel « algorithmes », qui doivent être rapide et ne pas beaucoup de temps les fonctions d'appel et si ceux-ci sont utilisés assez souvent pour être un problème de performance, alors JIT est très important.

0

La portabilité et l'indépendance de la plate-forme sont probablement les avantages les plus notables du bytecode par rapport au code natif.

Questions connexes