Il y a beaucoup de similitudes entre les deux mises en œuvre (et à mon avis: oui, ils sont tous les deux "machines virtuelles").
Pour une chose, ils sont à la fois basée sur la pile de l'ordinateur virtuel, avec pas de notion de "registres" comme nous avons l'habitude de voir dans un PROCESSEUR récent comme le x86 ou PowerPC. L'évaluation de toutes les expressions ((1 + 1) / 2) est réalisée en poussant des opérandes sur la "pile" et puis éclater ces opérandes hors de la pile chaque fois qu'une instruction (addition, division, etc) a besoin de consommer ces opérandes. Chaque instruction pousse ses résultats retour sur la pile.
C'est un moyen pratique de mettre en œuvre une machine virtuelle, parce qu'à peu près tous les CPU dans le monde a une pile, mais le nombre de registres est souvent différent (et certains registres sont spéciaux, et chaque instruction attend de ses opérandes dans des registres différents, etc).
Donc, si vous allez le modèle d'une machine abstraite, purement basée sur la pile modèle est une très bonne façon d'aller.
Bien sûr, de véritables machines ne fonctionnent pas de cette façon. Donc le compilateur JIT est chargé de l'exécution de "l'enregistrement" de bytecode opérations, essentiellement de la planification du réel registres du CPU pour contenir les opérandes et les résultats dès que possible.
Donc, je pense que c'est l'un des plus grands points communs entre le CLR et la JVM.
Comme pour les différences...
Une différence intéressante entre les deux implémentations, c'est que le CLR comprend des instructions pour la création de types génériques, et ensuite pour l'application paramétrique spécialisations de ces types. Ainsi, au moment de l'exécution, le CLR considère une Liste<int> pour être un genre complètement différent à partir d'une Liste<String>.
Sous les couvertures, elle utilise le même langage MSIL de référence de type de spécialisations (donc une List<String> utilise la même mise en œuvre que d'une Liste de<Object>, avec différents type-jette à l'API de frontières), mais la valeur de chaque type utilise son propre mise en œuvre (List<int> produit complètement différent du code de List<double>).
En Java, les types génériques sont purement un compilateur truc. La JVM n'a aucune notion de classes qui ont le type des arguments, et il est impossible d'effectuer paramétrique spécialisations au moment de l'exécution.
À partir d'un point de vue pratique, cela signifie que vous ne pouvez pas la surcharge de méthodes de Java sur les types génériques. Vous ne pouvez pas avoir deux méthodes différentes, avec le même nom, qui diffèrent seulement sur le fait qu'ils acceptent une List<String> ou une Liste de<Date>. Bien sûr, depuis le CLR connaît paramétrique types, il n'a pas de problème de manipulation des méthodes surchargées sur le type générique de spécialisations.
Au jour le jour, c'est la différence que je remarque le plus entre le CLR et le
JVM.
D'autres différences importantes incluent:
Le CLR a des fermetures (mise en œuvre en C# délégués). La JVM ne pas.
Le CLR a coroutines (mis en œuvre avec le C# 'rendement' mot-clé). La JVM ne pas.
Le CLR permet à l'utilisateur de code pour définir de nouveaux types de valeur (les structures), alors que la JVM fournit un fixe de collecte des types de valeur (byte, short, int, long, float, double, char, boolean) et seulement permet aux utilisateurs de définir une nouvelle référence-types (classes).
Le CLR fournit un soutien pour la déclaration et de la manipulation de pointeurs. Ceci est particulièrement intéressant, parce que les deux la JVM et le CLR employer stricte générationnel compactage garbage collector implémentations de leur mémoire de la stratégie de gestion. Dans des circonstances ordinaires, un strict de compactage GC a vraiment du mal avec les pointeurs, parce que quand vous déplacez une valeur à partir d'un emplacement mémoire à l'autre, tous les pointeurs (et des pointeurs de pointeurs) deviennent non valides. Mais le CLR fournit un "épinglage" mécanisme afin que les développeurs peuvent déclarer un bloc de code dans lequel le CLR n'est pas autorisé à déplacer certains pointeurs. Il est très pratique.
La plus grande unité de code dans la JVM est soit un "package", comme en témoigne la "protégés" mot-clé ou sans doute un BOCAL (c'est à dire Java ARchive), comme en témoigne être en mesure de spécifier un jar dans le classpath et de l'avoir traité comme un dossier de code. Dans le CLR, les classes sont regroupées en "assemblées", et le CLR fournit logique pour raisonner sur les et de manipuler des ensembles qui sont chargés dans des "domaines d'application", en offrant un sous-niveau de l'application sandbox pour l'allocation de mémoire et d'exécution du code).
Le CLR bytecode format (composé de MSIL des instructions et des métadonnées) a moins d'instructions types de la JVM. Dans la JVM, chaque opération unique (ajouter deux valeurs int, ajouter deux valeurs float, etc...) a sa propre instruction. Dans le CLR, toutes les instructions MSIL sont polymorphes (ajouter deux valeurs) et le compilateur JIT est responsable de déterminer les types des opérandes et de la création de la machine code. Je ne sais pas qui est la préférence de la stratégie. Les deux ont des compromis. Le HotSpot compilateur JIT, pour la JVM, peut utiliser une simple génération de code (il n'est pas nécessaire de déterminer l'opérande types, parce qu'ils sont déjà codées dans l'instruction), mais cela signifie qu'il a besoin d'un plus complexe bytecode format, avec plus d'instruction types.
J'ai été en utilisant Java (et d'admirer la JVM) pour une dizaine d'années maintenant.
Mais, à mon avis, le CLR est maintenant le supérieur de la mise en œuvre, dans presque tous les sens.