Pourquoi les Machines virtuelles sont-elles nécessaires?
je lisais cette question pour découvrir les différences entre la machine virtuelle Java et la réponse de .NET CLR et Benji m'a fait me demander pourquoi les Machines virtuelles sont nécessaires en premier lieu.
D'après ma compréhension de L'explication de Benji, le compilateur JIT d'une Machine virtuelle interprète le code intermédiaire dans le code d'assemblage réel qui tourne sur le CPU. La raison pour laquelle il doit faire ceci est parce que les CPU ont souvent différents nombres de registres et selon Benji, "certains registres sont spéciaux, et chaque instruction attend de ses opérandes dans des registres différents."Cela a du sens alors qu'il y a un besoin d'un interprète intermédiaire comme la Machine virtuelle pour que le même code puisse être exécuté sur n'importe quel CPU.
mais, si c'est le cas, alors ce que je ne comprends pas c'est pourquoi le code C ou c++ compilé dans le code machine est capable de tourner sur n'importe quel ordinateur tant que c'est le bon OS. Pourquoi alors un programme C que j'ai compilé sur ma machine Windows en utilisant un Pentium pourrait-il être exécuté sur mon autre machine Windows en utilisant un AMD?
si le code C peut fonctionner sur N'importe quel CPU alors quel est le but de la Machine virtuelle? Est-ce pour que le même code puisse être exécuté sur N'importe quel système D'exploitation? Je sais que Java a des versions VM sur pratiquement n'importe quel OS mais y a-t-il un CLR pour D'autres OS que Windows?
ou y a-t-il autre chose qui me manque? L'OS faire autre interprétation de code d'assemblage il tourne pour l'adapter au CPU particulier ou quelque chose?
je suis assez curieux de savoir comment tout cela fonctionne, donc une explication claire serait grandement apprécié.
Note: la raison pour laquelle je n'ai pas simplement posté mes questions en tant que Commentaires dans la question JVM vs CLR est que je n'ai pas assez de points pour poster des commentaires encore =B.
Edit: Merci pour toutes les réponses grands! Il semble donc que ce que je manquais était que bien que tout les processeurs ont des différences il existe une normalisation commune, principalement L'architecture X86, qui fournit un ensemble suffisamment important de caractéristiques communes pour que le code C compilé sur un processeur X86 fonctionne pour la plupart sur un autre processeur x86. Cela renforce la justification pour les Machines virtuelles, sans mentionner que j'ai oublié l'importance de la collecte des ordures.
10 réponses
les processeurs AMD et intel utilisent le même jeu d'instructions et la même architecture machine (du point de vue de l'exécution du code machine).
C et C++ Compilateurs compiler au code machine, avec des en-têtes appropriés à L'OS qu'ils sont ciblés. Une fois compilés, ils cessent de s'associer de quelque manière, forme ou forme que ce soit avec le langage dans lequel ils ont été compilés et ne sont que des exécutables binaires. (Il ya des artefacts taht peut montrer quelle langue il a été compilé à partir, mais ce n'est pas le point ici)
ainsi, une fois compilés, ils sont associés à la machine (X86, le jeu d'instructions et l'architecture intel et amd) et à L'OS.
c'est pourquoi ils peuvent fonctionner sur n'importe quelle machine x86 compatible, et N'importe quel OS compatible (win95 par winvista, pour certains logiciels).
cependant, ils ne peuvent pas fonctionner sur une machine OSX, même si elle fonctionne sur un processeur intel - le binaire n'est pas compatible à moins que vous n'exécutiez des logiciel d'émulation (comme parallels, ou une VM avec windows).
au-delà de cela, si vous voulez les exécuter sur un processeur ARM, ou MIPS, ou PowerPC, alors vous devez exécuter un émulateur de jeu d'Instructions machine complet qui interprète le code machine binaire De X86 dans n'importe quelle machine sur laquelle vous l'exécutez.
contraste avec ça .NET.
la machine virtuelle .NET est fabriquée comme s'il y avait de bien meilleurs processeurs dans la World-processeurs qui comprennent les objets, l'allocation de la mémoire et la collecte des ordures, et d'autres constructions de haut niveau. C'est une machine très complexe qui ne peut pas être construite directement en silicium maintenant (avec de bonnes performances) mais un émulateur peut être écrit qui lui permettra de fonctionner sur n'importe quel processeur existant.
soudainement, vous pouvez écrire un émulateur spécifique à une machine pour n'importe quel processeur que vous voulez lancer avec .NET, et alors N'importe quel programme .NET peut l'exécuter. Pas besoin de s'inquiéter pour L'OS ou l'architecture CPU sous-jacente - s'il y a une VM.net, alors le logiciel s'exécute.
mais allons un peu plus loin - une fois que vous avez ce langage commun, pourquoi ne pas faire des compilateurs qui convertissent n'importe quel autre langage écrit en lui?
donc maintenant vous pouvez avoir un C, C#, C++, Java, javascript, Basic, python, lua, ou tout autre compilateur de langue qui convertit le code écrit pour qu'il tourne sur cette machine virtuelle.
vous avez dissocié le machine à partir de la langue de 2 degrés, et avec peu de travail, vous permettez à n'importe qui d'écrire n'importe quel code et le faire fonctionner sur n'importe quelle machine, aussi longtemps qu'un compilateur et une VM existe pour cartographier les deux degrés de séparation.
si vous vous demandez toujours pourquoi c'est une bonne chose, considérez les premières machines DOS, et ce que réel "de Microsoft 1519260920" contribution au monde était:
Autocad devait écrire des pilotes pour chaque imprimante à laquelle ils pouvaient imprimer. Donc n'lotus 1-2-3. En fait, si vous vouliez que votre logiciel soit imprimé, vous deviez écrire vos propres pilotes. S'il y avait 10 imprimantes et 10 programmes, alors 100 morceaux différents du même code devaient être écrits séparément et indépendamment.
ce que windows 3.1 a essayé d'accomplir (avec GEM, et tant d'autres couches d'abstraction) est de faire en sorte que le fabricant de l'imprimante ait écrit un pilote pour son imprimante, et que le programmeur ait écrit un pilote pour windows classe d'imprimante.
maintenant avec 10 programmes et 10 imprimantes, seulement 20 morceaux de code doivent être écrits, et puisque le côté microsoft du code était le même pour tout le monde, puis des exemples de MS signifiait que vous aviez très peu de travail à faire.
maintenant, un programme n'était pas limité aux 10 imprimantes qu'ils choisissaient de prendre en charge, mais à toutes les imprimantes dont les fabricants fournissaient des pilotes pour windows.
Le même problème se produit dans le développement de l'application. Il y a des applications vraiment soignées que je ne peux pas utiliser parce que je n'utilise pas de MAC. Il ya une tonne de duplication (combien de classe mondiale de traitement de texte-nous vraiment besoin?).
Java était destiné à corriger cela, mais il avait de nombreuses limites, dont certaines ne sont pas vraiment résolus.
.NET est plus proche, mais personne ne développe de VMs de classe mondiale pour les plateformes autres que Windows (mono est si proche... et pourtant pas tout à fait là).
So... C'est pourquoi nous avons besoin de VMs. Parce que je ne veux pas me limiter à un public plus restreint simplement parce qu'ils ont choisi une combinaison OS/machine différente de la mienne.
- Adam
votre hypothèse que le code C peut s'exécuter sur n'importe quel processeur est incorrecte. Il y a des choses comme les registres et l'endianness qui feront que les programmes compilés C ne fonctionneront pas du tout sur une plate-forme, alors qu'ils pourraient fonctionner sur une autre.
cependant, il y a certaines similitudes que les processeurs partagent, par exemple, les processeurs Intel x86 et les processeurs AMD partagent un ensemble de propriétés assez grand pour que la plupart du code compilé contre l'un tourne sur l'autre. Toutefois, si vous voulez l'utilisation du processeur propriétés spécifiques, alors vous avez besoin d'un compilateur ou d'un ensemble de bibliothèques qui le fera pour vous.
quant à la raison pour laquelle vous voudriez une machine virtuelle, au-delà de la déclaration qu'elle traitera les différences dans les processeurs pour vous, il y a aussi le fait que les machines virtuelles offrent des services de code qui ne sont pas disponibles pour les programmes compilés en C++ (non gérés) aujourd'hui.
le service le plus important offert est la collecte des ordures, offert par le La CLR et la JVM. Ces deux machines virtuelles vous offrons ce service gratuitement. Ils gèrent la mémoire pour toi.
des choses comme la vérification des limites, les violations de l'accès (bien qu'elles soient encore possibles, elles sont extrêmement difficiles) sont également offertes.
le CLR offre également une forme de sécurité de code pour vous.
aucun de ceux-ci ne sont offerts dans le cadre de l'environnement d'exécution de base pour un certain nombre d'autres langues qui ne fonctionnent pas avec un la machine virtuelle.
vous pourriez obtenir certains d'entre eux en utilisant des bibliothèques, mais alors cela vous force dans un modèle d'utilisation avec la bibliothèque, alors que dans .NET et les services Java qui vous sont offerts par le CLR et JVM sont cohérents dans leur accès.
essentiellement, il permet de "code géré", ce qui signifie exactement ce qu'il dit - la machine virtuelle gère le code pendant qu'il court. Les trois principaux avantages de cette méthode sont la compilation juste à temps, la gestion des indicateurs/collecte des ordures et le contrôle de la sécurité.
pour la compilation juste-à-temps, la machine virtuelle regarde le code exécuter et comme le code est exécuté plus souvent, il est ré-activé pour exécuter plus rapidement. Tu ne peux pas faire ça avec du code natif.
Les pointeurs managéssont également plus faciles à optimiser car la machine virtuelle les suit au fur et à mesure, les gérant de différentes manières en fonction de leur taille et de leur durée de vie. C'est difficile de faire ça en C++ parce qu'on ne peut pas vraiment dire où un pointeur va aller juste en lisant le code.
la sécurité est explicite, la machine virtuelle empêche le code de faire des choses qu'il ne devrait pas parce qu'il regarde. Personnellement, je pense que c'est probablement la la plus grande raison pour laquelle Microsoft a choisi le code géré pour C#.
fondamentalement mon point est, parce que la machine virtuelle peut regarder le code comme il arrive, il peut faire des choses qui rendent la vie plus facile sur le programmeur et rendre le code plus rapide.
la plupart des compilateurs, même natifs, utilisent une sorte de langage intermédiaire.
ceci est principalement fait pour réduire les coûts de construction du compilateur. Il existe de nombreuses (N) langues de programmation dans le monde. Il existe également de nombreuses plates-formes (M) hard ware dans le monde. Si les compilateurs fonctionnaient sans utiliser un langage intermédiaire, le nombre total de "compilateurs" qui devraient être écrits pour supporter toutes les langues sur toutes les plateformes matérielles serait N*m.
Cependant, en définissant un langage intermédiaire et en divisant un compilateur en 2 parties, une extrémité avant et une extrémité arrière, avec l'extrémité avant compilant le code source en IL et l'extrémité arrière compilant IL en code machine, vous pouvez vous en tirer avec l'écriture seulement n+m compilateurs. Il s'agit en fin de compte d'économies considérables.
la grande différence entre les compilateurs CLR / JVM et les compilateurs de code natifs est la façon dont les compilateurs front end et back end sont reliés entre eux. Dans un code natif compilateur les deux composants sont généralement combinés dans le même exécutable, et les deux sont exécutées lorsque le programmeur hits "construire" dans l'IDE.
avec des compilateurs CLR / JVM, l'avant et l'arrière sont exécutés à des moments différents. La partie frontale est exécutée au moment de la compilation, produisant L'IL qui est effectivement expédié aux clients. La partie arrière est alors incorporée dans un composant séparé qui est invoqué à l'exécution.
Donc, cela amène l'autre question, " Quels sont les avantages de retarder la compilation back end jusqu'à l'exécution?"
la réponse est:"cela dépend".
en retardant la compilation back end jusqu'à l'exécution, il devient possible d'envoyer un ensemble de binaires pouvant fonctionner sur plusieurs plates-formes matérielles. Il permet également aux programmes de tirer parti des améliorations apportées à la technologie de compilation du back end sans être réaffectés. Il peut également fournir une base efficace pour mise en œuvre de nombreuses fonctionnalités linguistiques dynamiques. Enfin, il offre la possibilité d'introduire des contraintes de sécurité et de fiabilité entre bibliothèques compilées séparément, reliées dynamiquement (dlls) qui ne sont pas possibles avec une compilation de code machine initiale.
Cependant, il y a aussi des inconvénients. L'analyse nécessaire pour mettre en œuvre des optimisations étendues des compilateurs peut être coûteuse. Cela signifie que les back-ends" JIT " font souvent moins d'optimisations que les back-ends initiaux. Ce peut nuire à la performance. En outre, la nécessité d'invoquer le compilateur à l'exécution augmente également le temps nécessaire pour charger les programmes. Les programmes générés avec des compilateurs" initiaux " n'ont pas ces problèmes.
tout d'abord, le code machine n'est pas la forme la plus basse d'instructions pour un cpu. De nos jours, les CPU x86 interprètent eux-mêmes l'instruction X86 réglée dans un autre format interne à l'aide d'un microcode. Les seules personnes qui programment réellement le microcode sont les types d'ingénieurs de développement de puce, qui imitent fidèlement et sans douleur la puce d'instruction x86 legacy pour atteindre une performance maximale en utilisant les technologies d'aujourd'hui.
types de développeur ont toujours été l'ajout de couches supplémentaires de les abstractions en raison du pouvoir et des caractéristiques qu'elles apportent. Après tout, de meilleures abstractions permettent d'écrire de nouvelles applications plus rapidement et de manière plus fiable. Les entreprises ne se soucient pas de ce qu'ils codent ou comment ils ressemblent qu'ils veulent juste le travail fait de manière fiable et rapide. Est-ce vraiment important si la version C d'une application prend quelques millisecondes de moins mais finit par prendre le double du temps de développement ?
la question de la vitesse est presque un argument non les applications qui servent des millions de personnes sont écrites dans des plates - formes/langues comme java-eg GMail, GMaps. Oubliez quelle langue / plate-forme est la plus rapide. Ce qui est plus important, c'est que vous utilisiez les bons algorithmes, que vous écriviez le code effectif et que vous obteniez le travail.
AMD et les processeurs Intel ont tous deux une architecture x86, si vous voulez exécuter un programme c/c++ sur une architecture différente, vous devez utiliser un compilateur pour cette architecture, le même exécutable binaire ne sera pas exécuté sur différentes architectures de processeurs.
d'une manière très simplifiée, C'est parce Qu'Intel et AMD implémentent le même langage d'assemblage, avec le même nombre de registres, etc...
donc votre compilateur C compile du code pour travailler sur Linux. Cette assemblée utilise un Linux ABI , aussi longtemps que le programme de compilation est exécuté sur Linux, sur x86 assembly, et la bonne fonction signature, alors tout est dandy.
essayez maintenant de prendre ce code compilé, et collez-le sur, disons Linux / PPC (par exemple Linux sur un vieux iBook). Ce n'est pas d'aller travailler. Où comme un programme Java le ferait parce que la JVM a été mise en œuvre sur la plate-forme Linux/PPC.
assemblage langauge de nos jours est fondamentalement une autre interface qu'un programmeur peut programmer. x86 (32-bit) vous permet d'accéder à eax,ebx,ecx,edx pour les registres integer à usage général, et f00-f07 pour la virgule flottante. Dans les coulisses, le CPU a en fait une centaine d'autres registres, et a mélangé ces trucs autour pour réduire la performance.
vous avez raison dans votre analyse, java ou C# auraient pu être conçus pour compiler directement pour fonctionner sur n'importe quelle machine, et seraient probablement plus rapides s'ils le faisaient. Mais l'approche de la machine virtuelle donne le contrôle complet de l'environnement dans lequel votre code s'exécute, la VM crée un bac à sable sécurisé qui permet seulement aux commandes avec le bon accès de sécurité d'effectuer potentiellement dommageable code - comme le changement de mot de passe, ou la mise à jour D'un bootsector HD. Il y a beaucoup d'autres avantages, mais c'est la killer raison. Vous ne pouvez pas obtenir un StackOverflow en C# ...
je pense que la prémisse de votre question est valide - Vous n'êtes certainement pas le premier à poser cette question. Alors regarde http://llvm.org pour voir une approche alternative (qui est maintenant un projet en cours? ou sponsorisé par Apple)