Question

Je lisais cette question pour connaître 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.

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 s'exécute sur le processeur. Cela s'explique par le fait que les processeurs ont souvent un nombre différent de registres et, selon Benji, & "Certains registres ont une fonction spécifique et chaque instruction attend ses opérandes dans différents registres. &"; Il est donc logique qu’un interpréteur intermédiaire tel que la machine virtuelle soit nécessaire pour que le même code puisse être exécuté sur n’importe quel processeur.

Mais si tel est le cas, je ne comprends pas pourquoi le code C ou C ++ compilé en code machine peut être exécuté sur n’importe quel ordinateur, à condition que le système d’exploitation utilisé soit correct. Pourquoi alors un programme C que j'ai compilé sur une machine Windows utilisant un Pentium pourrait-il être exécuté sur une autre machine Windows utilisant un processeur AMD?

Si le code C peut être exécuté sur n’importe quel processeur, quel est le but de la machine virtuelle? Est-ce que le même code peut être exécuté sur n'importe quel système d'exploitation? Je sais que Java a des versions de machine virtuelle sur à peu près n'importe quel système d'exploitation, mais existe-t-il un CLR pour d'autres systèmes d'exploitation que Windows?

Ou y a-t-il autre chose qui me manque? Le système d'exploitation interprète-t-il autrement le code d'assemblage qu'il exécute pour l'adapter à la CPU en question ou à un autre?

Je suis assez curieux de savoir comment cela fonctionne. Une explication claire serait donc grandement appréciée.

Remarque: si je n'ai pas simplement posté mes requêtes sous forme de commentaires dans la question JVM contre CLR, c'est parce que je n'ai pas assez de points pour publier des commentaires pour le moment = b.

Edit: Merci pour toutes les bonnes réponses! Il me semble donc que ce qui me manquait, c’est que, bien que tous les processeurs présentent des différences, il existe une normalisation commune, principalement l’architecture X86, qui fournit un ensemble assez important de fonctionnalités communes pour que le code C compilé sur un processeur X86 fonctionne généralement. sur un autre processeur X86. Cela renforce la justification des machines virtuelles, sans oublier d’oublier l’importance du ramassage des ordures.

Était-ce utile?

La solution

Les processeurs AMD et intel utilisent le même jeu d'instructions et la même architecture (du point de vue de l'exécution du code machine).

Les compilateurs C et C ++ compilent en code machine, avec des en-têtes appropriés au système d’exploitation auquel ils sont destinés. Une fois compilés, ils cessent de s’associer de quelque manière que ce soit avec le langage dans lequel ils ont été compilés et ne sont que des exécutables binaires. (Il y a des artefacts qui peuvent indiquer le langage à partir duquel il a été compilé, mais ce n'est pas le problème ici.)

Ainsi, une fois compilés, ils sont associés à la machine (X86, le jeu d’instructions intel et amd et son architecture) et au système d’exploitation.

C’est pourquoi ils peuvent fonctionner sur n’importe quel ordinateur compatible x86, et n’importe quel système d’exploitation compatible (de win95 à winvista, pour certains logiciels).

Toutefois, ils ne peuvent pas fonctionner sur un ordinateur OSX, même s’il s’applique sur un processeur Intel. Le fichier binaire n’est compatible que si vous exécutez un logiciel d’émulation supplémentaire (tel que des parallèles ou une machine virtuelle avec Windows).

Au-delà de cela, si vous souhaitez les exécuter sur un processeur ARM, MIPS ou PowerPC, vous devez exécuter un émulateur de jeu d'instructions complet de la machine qui interprète le code machine binaire de X86 dans la machine sur laquelle vous l'exécutez. sur.

Comparez cela avec .NET.

La machine virtuelle .NET est fabriquée comme s'il y avait de bien meilleurs processeurs dans le monde: des processeurs qui comprennent les objets, l'allocation de mémoire et le garbage collection, ainsi que d'autres constructions de haut niveau. C'est une machine très complexe qui ne peut pas être construite directement dans le silicium maintenant (avec de bonnes performances), mais un émulateur peut être écrit pour lui permettre de fonctionner sur n'importe quel processeur existant.

Tout à coup, vous pouvez écrire un émulateur spécifique à une machine pour tout processeur sur lequel vous souhaitez exécuter .NET. Ensuite, TOUT programme .NET pourra être exécuté. Inutile de vous préoccuper du système d'exploitation ou de l'architecture de la CPU sous-jacente - s'il existe une machine virtuelle .NET, le logiciel s'exécutera.

Mais allons un peu plus loin - une fois que vous avez ce langage commun, pourquoi ne pas créer des compilateurs qui convertissent tout autre langage écrit en celui-ci?

Donc, vous pouvez maintenant avoir un compilateur de langage C, C #, C ++, Java, javascript, Basic, pua, lua ou tout autre langage qui convertit le code écrit afin qu’il soit exécuté sur cette machine virtuelle.

Vous avez dissocié la machine de la langue de 2 degrés et, avec peu de travail, vous permettez à quiconque d'écrire du code et de le faire fonctionner sur n'importe quelle machine, tant qu'un compilateur et une machine virtuelle existent pour mapper les deux. degrés de séparation.

Si vous vous demandez toujours pourquoi c'est une bonne chose, pensez aux machines DOS antérieures et à la véritable vraie contribution de Microsoft au monde:

Autocad devait écrire des pilotes pour chaque imprimante sur laquelle il pouvait imprimer. De même que 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, il fallait alors écrire séparément et indépendamment 100 différents types de code.

Ce que Windows 3.1 a tenté d'accomplir (avec GEM et de nombreuses autres couches d'abstraction), c'est que le fabricant de l'imprimante ait écrit un pilote pour son imprimante et que le programmeur ait écrit un pilote pour la classe d'imprimantes Windows.

Maintenant, avec 10 programmes et 10 imprimantes, il ne reste plus que 20 morceaux de code à écrire. Comme le code Microsoft était le même pour tout le monde, les exemples fournis par MS signifiaient que vous aviez très peu de travail à faire.

Désormais, un programme ne se limite pas aux 10 imprimantes qu’ils ont choisi de prendre en charge, mais à toutes les imprimantes dont les fabricants fournissent des pilotes pour les fenêtres.

Le même problème se produit lors du développement d'applications. Il existe de très bonnes applications que je ne peux pas utiliser car je n'utilise pas de MAC. Il y a une tonne de duplication (combien de traitements de texte de classe mondiale avons-nous vraiment besoin?).

Java était censé résoudre ce problème, mais il comportait de nombreuses limitations, dont certaines ne sont pas réelles.lly résolu.

.NET est plus proche, mais personne ne développe de machines virtuelles de classe mondiale pour des plates-formes autres que Windows (le mono est si proche… et pourtant pas tout à fait là).

Alors ... C'est pourquoi nous avons besoin de machines virtuelles. Parce que je ne veux pas me limiter à un public restreint simplement parce qu'ils ont choisi une combinaison système d'exploitation / machine différente de la mienne.

-Adam

Autres conseils

Votre hypothèse selon laquelle le code C peut être exécuté sur n’importe quel processeur est incorrecte. Il existe des éléments tels que les registres et l’endianness qui empêcheront les programmes C compilés de fonctionner sur une plate-forme, alors que cela pourrait fonctionner sur une autre.

Toutefois, les processeurs partagent certaines similitudes, par exemple, les processeurs Intel x86 et AMD partagent un ensemble de propriétés suffisamment important pour que la plupart du code compilé avec l'une s'exécute sur l'autre. Toutefois, si vous souhaitez utiliser des propriétés spécifiques au processeur, vous avez besoin d’un compilateur ou d’un ensemble de bibliothèques qui le fera pour vous.

Pour ce qui est de la raison pour laquelle vous voulez une machine virtuelle, outre la déclaration selon laquelle elle gérera les différences de processeurs, il existe également le fait que les machines virtuelles offrent des services sous forme de code qui ne sont pas disponibles pour les programmes compilés en C ++ (non gérées). ) aujourd'hui.

Le service le plus important proposé est le ramassage des ordures, proposé par le CLR et la JVM. Ces deux machines virtuelles vous offrent ce service gratuitement. Ils gèrent la mémoire pour vous.

Des fonctionnalités telles que la vérification des limites, les violations d'accès (même si elles sont possibles, sont extrêmement difficiles) sont également proposées.

Le CLR offre également une forme de code de sécurité pour vous.

Aucune de ces options n'est proposée dans l'environnement d'exécution de base pour un certain nombre d'autres langues qui ne fonctionnent pas avec une machine virtuelle.

Vous pouvez en obtenir certains en utilisant des bibliothèques, mais cela vous oblige à adopter un mode d'utilisation avec la bibliothèque, alors que les services .NET et Java qui vous sont proposés par le biais du CLR et de la JVM ont un accès cohérent.

En gros, il permet le "code géré", ce qui signifie exactement ce qu'il dit: la machine virtuelle gère le code pendant son exécution. Cette compilation présente trois avantages principaux: compilation juste à temps, pointeurs gérés / récupération de place et contrôle de la sécurité.

Pour la compilation juste à temps, la machine virtuelle surveille l'exécution du code. Ainsi, à mesure que le code s'exécute plus souvent, il est réoptimisé pour s'exécuter plus rapidement. Vous ne pouvez pas faire cela avec du code natif.

Les pointeurs gérés sont également plus faciles à optimiser car la machine virtuelle les suit au fur et à mesure de leur parcours, en les gérant de différentes manières en fonction de leur taille et de leur durée de vie. Il est difficile de faire cela en C ++ parce que vous ne pouvez pas vraiment savoir où un pointeur va aller en lisant le code.

La sécurité s'explique d'elle-même, la machine virtuelle empêche le code de faire ce qu'il ne devrait pas faire parce qu'il surveille. Personnellement, je pense que c'est probablement la principale raison pour laquelle Microsoft a choisi le code managé pour C #.

Mon point essentiel est que, parce que la machine virtuelle peut voir le code tel quel, elle peut faire des choses qui simplifient la vie du programmeur et rendent le code plus rapide.

La plupart des compilateurs, même les compilateurs de code natif, 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 (M) plates-formes matérielles dans le monde. Si les compilateurs travaillent sans utiliser de langage intermédiaire, le nombre total de & Quot; compilateurs & Quot; qui aurait besoin d’être écrit pour prendre en charge toutes les langues sur toutes les plates-formes matérielles serait N * M.

Cependant, en définissant un langage intermédiaire et en divisant un compilateur en 2 parties, un frontal et un back-end, le code source compilant front-end en IL et le back-end compilant IL en code machine vous permettent de vous évader en écrivant uniquement les compilateurs N + M. Cela finit par être une énorme économie de coûts.

La grande différence entre les compilateurs CLR / JVM et les compilateurs de code natif réside dans la manière dont les compilateurs front-end et back-end sont liés. Dans un compilateur de code natif, les deux composants sont généralement combinés dans le même exécutable et sont exécutés lorsque le programmeur exécute & "; Construction &"; dans l'IDE.

Avec les compilateurs CLR / JVM, le front-end et le back-end sont exécutés à des moments différents. Le front-end est exécuté au moment de la compilation, ce qui produit une IL qui est réellement envoyée aux clients. Le back-end est ensuite incorporé dans un composant séparé appelé à l'exécution.

Cela pose donc une autre question, & "Quels sont les avantages de retarder la compilation en arrière-plan jusqu'à l'exécution &";

La réponse est: & "Cela dépend &";

.

En retardant la compilation en arrière-plan jusqu'à l'exécution, il devient possible d'expédier un ensemble de fichiers binaires pouvant s'exécuter sur plusieurs plates-formes matérielles. Il permet également aux programmes de tirer parti des améliorations apportées à la technologie de compilation d’arrière-plan sans être redéployés. Il peut également fournir une base pour la mise en œuvre efficace de nombreuses fonctionnalités de langage dynamiques. Enfin, il offre la possibilité d’introduire des contraintes de sécurité et de fiabilité entre des bibliothèques (dll) liées dynamiquement, compilées séparément, ce qui n’est pas possible avec la compilation de code machine d’avance.

Cependant, il y a aussi des inconvénients. L'analyse nécessaire pour mettre en œuvre des optimisations de compilateur étendues peut être coûteuse. Cela signifie que & "; JIT &"; les back-end feront souvent moins d'optimisations que les backends en amont. Cela peut nuire aux performances. En outre, la nécessité d'appeler le compilateur au moment de l'exécution augmente également le temps nécessaire au chargement des programmes. Programmes générés avec & Quot; upfront & Quot; les compilateurs n'ont pas ces problèmes.

Tout d’abord, le code machine n’est pas la forme la plus basse d’instructions pour un processeur. De nos jours, les centres de traitement x86 interprètent eux-mêmes le jeu d'instructions X86 dans un autre format interne utilisant le microcode. Les seules personnes qui programment réellement le microcode sont les types d’ingénieurs développeurs, qui émulent fidèlement et sans douleur la puce d’instruction x86 héritée pour obtenir des performances maximales à l’aide des technologies actuelles.

Les types de développeurs ont toujours ajouté des couches supplémentaires d’abstractions en raison de la puissance et des fonctionnalités qu’ils apportent. Après tout, de meilleures abstractions permettent d’écrire de nouvelles applications plus rapidement et de manière plus fiable. Les entreprises ne s’inquiètent pas de ce à quoi elles ressemblent ni de la façon dont elles codent, elles veulent simplement que le travail soit effectué de manière fiable et rapide. Est-ce vraiment important si la version C d'une application prend quelques millisecondes en moins mais finit par prendre le double de temps pour se développer?

La question de la rapidité n’est quasiment pas un argument car de nombreuses applications d’entreprise destinées à des millions de personnes sont écrites dans des plateformes / langages tels que java - par exemple, GMail, GMaps. Oubliez la langue / plate-forme la plus rapide. Ce qui est plus important, c’est que vous utilisiez les algorithmes appropriés, écrivez un code efficace et accomplissiez le travail voulu.

Les processeurs AMD et Intel ont tous deux une architecture x86. Si vous souhaitez 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 fonctionnera pas avec différentes architectures de processeur.

  

Je sais que Java a des versions de machine virtuelle sur pratiquement tous les systèmes d'exploitation, mais existe-t-il un CLR pour d'autres systèmes d'exploitation que Windows?

Mono

De 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 etc ...

Votre compilateur C compile donc le code pour fonctionner sous Linux. Cet assemblage utilise un ABI Linux Linux , donc tant que le programme de compilation est exécuté sur Linux , sur l’assemblage x86 et la signature de fonction correcte, alors tout est dandy.

Maintenant, essayez de prendre ce code compilé et collez-le, dites Linux / PPC (par exemple, Linux sur un ancien iBook). Cela ne va pas au travail. Où en tant que programme Java, car la machine virtuelle Java a été implémentée sur la plate-forme Linux / PPC.

La langue d’assemblage est aujourd’hui une autre interface qu'un programmeur peut programmer. x86 (32 bits) vous permet d’accéder à eax, ebx, ecx, edx pour les registres d’entiers généraux, et f00-f07 pour les virgules flottantes. Dans les coulisses, le processeur possède en réalité une centaine de registres supplémentaires, et il mélange ces informations pour en extraire les performances.

Vous avez raison dans votre analyse, java ou C # aurait pu être conçu pour être compilé directement sur n'importe quelle machine et serait probablement plus rapide s'il le faisait. Mais l’approche de la machine virtuelle donne un contrôle complet de l’environnement dans lequel votre code s’exécute. La machine virtuelle crée un sandbox sécurisé qui permet uniquement aux commandes disposant du droit d’accès sécurisé d’exécuter du code potentiellement dommageable - comme changer de mot de passe ou mettre à jour un secteur de démarrage HD. Il y a beaucoup d'autres avantages, mais c'est la raison qui tue. Vous ne pouvez pas obtenir un StackOverflow en C # ...

Je pense que la prémisse de votre question est valable - vous n'êtes certainement pas le premier à poser cette question. Découvrez http://llvm.org pour découvrir une autre approche (qui est maintenant un projet en cours d'exécution ou sponsorisé par Apple)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top