La vérification de code octet arriver deux fois? [dupliquer]

cette question a déjà une réponse ici:

donc je suis un peu confus en ce qui concerne la vérification du bytecode qui se passe à l'intérieur d'une JVM. Selon le livre de Deitel et Deitel , un Le programme Java passe par cinq phases (édition, compilation, chargement, vérification et exécution) (chapitre 1). Le vérificateur de bytecode vérifie le code de bytecode au cours de l'étape de "vérification". Le livre ne mentionne nulle part que le vérificateur de bytecode fait partie du classloader.

toutefois selon docs de l'oracle , le classloader exécute la tâche de chargement, de liaison et d'initialisation, et pendant le processus de liaison il doit vérifier le bytecode.

maintenant, sont la vérification de bytecode dont Deitel et Deitel parle, et la vérification de bytecode que ce document oracle parle, le même processus?

ou la vérification du bytecode se produit-elle deux fois, une fois au cours du processus de liaison et l'autre par le vérificateur du bytecode?

image décrivant les phases d'un programme java comme mentionné dans le livre de Dietel et Dietel.(J'ai emprunté cette photo de l'un des Réponses ci-dessous par nobalG :) ) enter image description here

30
demandé sur nobalG 2014-08-28 10:04:43

5 réponses

vous pouvez comprendre la vérification du code octet en utilisant ce diagramme qui est expliqué en détail dans Oracle docs

enter image description here

vous constaterez que la vérification du code octet n'a lieu qu'une seule fois et non deux fois.""

l'illustration montre le flux de données et le contrôle du langage Java code source à travers le compilateur Java, vers le chargeur de classe et bytecode verificateur et donc sur la machine virtuelle Java, qui contient l'interprète et le système d'exécution. La question importante est de que le chargeur de classe Java et le vérificateur de bytecode ne hypothèses sur la source primaire du flux de bytecode--le code peut venir à partir du système local, ou il peut avoir traversé la moitié autour de la planète. Le vérificateur de bytecode agit comme une sorte de gatekeeper: il s'assure que le code passé à L'interpréteur Java est dans un état convenable pour être exécuté et peut courir sans crainte de briser la Java interprète. Le code importé ne peut être exécuté par aucun moyen jusqu'à ce qu'il ait passé les tests du vérificateur. Une fois que le vérificateur est fait, un certain nombre de propriétés importantes sont connus:

  • Il n'y a pas d'opérande débordements de pile ou underflows
  • les types de paramètres de toutes les instructions de bytecode sont connus pour être toujours corrects
  • champ D'objet on sait que les accès sont légaux--privés, publics ou protégés

alors que toutes ces vérifications semblent excessivement détaillées, d'ici le le vérificateur de bytecode a fait son travail, L'interpréteur Java peut procédez, en sachant que le code sera exécuté en toute sécurité. Sachant que ces propriétés rend l'interpréteur Java beaucoup plus rapide, parce qu'il ne vérifier quoi que ce soit. Il n'y a pas de vérification de type opérande et pas de pile débordement de contrôles. L'interprète peut donc fonction à pleine vitesse sans compromettre la fiabilité.

EDIT: -

From Oracle Docs Section 5.3.2 :

lorsque la méthode loadClass du chargeur de classe L est invoquée avec le nom N d'une classe ou d'une interface C à charger, L doit effectuer l'un des les deux opérations suivantes pour charger C:

  • le chargeur de classe L peut créer un tableau d'octets représentant C comme les octets d'une structure de ClassFile (§4.1); il doit alors invoquer la méthode defineClass de class Classcloader. Invocating defineClass provoque la machine virtuelle Java à dériver une classe ou une interface indiqué par N en utilisant L à partir du tableau d'octets en utilisant l'algorithme au §5.3.5.
  • le chargeur de classe L peut déléguer le chargement de C à un autre chargeur de classe L'. C'est accompli en passant l'argument N directement ou indirectement à l'invocation d'une méthode sur L' (généralement la méthode loadClass). Le résultat de l'invocation est C.

comme correctement commenté par Holger, en essayant de l'expliquer plus à l'aide d'un exemple :

static int factorial(int n)
{
int res;
for (res = 1; n > 0; n--) res = res * n;
return res;
}

le code de byte correspondant serait

method static int factorial(int), 2 registers, 2 stack slots
0: iconst_1 // push the integer constant 1
1: istore_1 // store it in register 1 (the res variable)
2: iload_0 // push register 0 (the n parameter)
3: ifle 14 // if negative or null, go to PC 14
6: iload_1 // push register 1 (res)
7: iload_0 // push register 0 (n)
8: imul // multiply the two integers at top of stack
9: istore_1 // pop result and store it in register 1
10: iinc 0, -1 // decrement register 0 (n) by 1
11: goto 2 // go to PC 2
14: iload_1 // load register 1 (res)
15: ireturn // return its value to caller

noter que la plupart des les instructions dans JVM sont dactylographiées.

il est à noter que le bon fonctionnement de la JVM n'est garanti que si le code remplit au moins les conditions suivantes:

  • Type rectitude: les arguments d'une instruction sont toujours de la types attendus par l'instruction.
  • Aucun débordement de pile ou de dépassement de capacité: une instruction de ne jamais pop un argument hors une pile vide, ni pousse un résultat sur une pile complète (dont la taille être égale à la taille maximale de la pile déclarée pour la méthode).
  • Confinement du Code
  • : le compteur de programmes doit toujours pointer à l'intérieur du code de la méthode, au début d'une instruction valide encodage (pas de chute à la fin du code de la méthode; pas de branches dans le code milieu d'une instruction de codage).
  • initialisation de Registre: une charge à partir d'un registre doit toujours suivre à moins d'un magasin dans ce registre; en d'autres termes, les registres qui ne pas correspondent aux paramètres de la méthode ne sont pas initialisés sur la méthode entrée, et c'est une erreur de charger à partir d'un registre non initialisé.
  • initialisation de L'objet: lorsqu'une instance d'une Classe C est créée, on des méthodes d'initialisation pour la classe C (correspondant à la les constructeurs pour cette classe) doivent être invoqués avant la classe instance peut être utilisée.

le but de la vérification du code octet est de vérifier ces conditions une fois pour toutes , par analyse statique du code octet au moment de la charge. Le code octet qui passe la verfification peut alors être exécuté plus rapidement.

aussi pour noter que le but de la vérification du code octet est de déplacer la vérification de verfification ci-dessus du temps d'exécution au temps de chargement.

l'explication ci-dessus est tirée de vérification du bytecode Java: algorithmes et formalisations

21
répondu Rahul Tripathi 2014-08-28 16:23:22

Pas de.

From the JVM Spec 4.10 :

même si un compilateur pour le langage de programmation Java ne doit produire que des fichiers de classe qui satisfont à toutes les contraintes statiques et structurelles des sections précédentes, la machine virtuelle Java n'a aucune garantie que tout fichier qu'on lui demande de charger a été généré par ce compilateur ou est correctement formé.

et procède ensuite spécifier le processus de vérification.

et JVM Spec 5.4.1 :

La vérification

(§4.10) garantit que la représentation binaire d'une classe ou d'une interface est structurellement correcte (§4.9). La vérification peut entraîner le chargement de classes et d'interfaces supplémentaires (§5.3), mais il n'est pas nécessaire qu'elles soient vérifiées ou préparées.

la section spécifiant les références de liaison §4.10-pas comme un processus séparé mais partie du chargement des classes.

La JVM et JLS sont de grands documents lorsque vous avez une question comme ça.

9
répondu jdphenix 2014-08-28 06:11:20

Aucun de ces Deux temps de la vérification

Non , en ce qui concerne la vérification,regardez attentivement comment le programme écrit en java passe par diverses phases dans l'image suivante,vous verrez qu'il n'y a pas de vérification à deux temps mais le code est vérifié une seule fois.

enter image description here

  • EDIT – Le programmeur écrit le programme (de préférence sur un bloc-notes) et l'enregistre comme une ‘.java’, qui est ensuite utilisée pour compilation, par le compilateur.
  • compiler – le compilateur prend ici le".java fichier, compile et recherche les erreurs éventuelles dans le cadre du programme. Si il trouve toute erreur, elle le signale au programmeur. Si aucune erreur n' est là, puis le programme est converti en bytecode et enregistré comme un".la classe de fichier.

  • LOAD – maintenant la fonction principale du composant appelé "Class Loader" est de charger le code octet dans la JVM. Il n'exécute pas encore le code, mais il le charge dans la mémoire du JVM.

  • vérifier - après chargement du code, la sous-partie de la JVM appelée "Byte" Le vérificateur de Code vérifie le bytecode et vérifie pour sa authenticité. Il vérifie également si le bytecode possède un tel code qui pourrait conduire à des malveillants résultat. Cette composante de la JVM assure la sécurité.

  • EXECUTE – le composant suivant est le moteur D'exécution. Exécution le moteur interprète le code ligne par ligne en utilisant le juste à temps (JIT) compilateur. Le compilateur JIT exécute l'exécution assez rapidement mais consomme de la mémoire cache supplémentaire.

9
répondu nobalG 2014-09-30 06:13:39

la spécification liste 4 phases dans la vérification bytecode. Ces étapes sont fonctionnellement distinctes, à ne pas confondre avec de répéter la même chose. Tout comme un compilateur multi-passes utilise chaque passe pour se configurer pour la prochaine passe, les phases ne sont pas de la répétition, mais sont orchestrées pour un seul but général, chaque phase accomplit certaines tâches.

à moins que le bytecode ne soit modifié, il n'y a aucune raison de le vérifier deux fois.

la vérification est décrit ici.

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10

5
répondu codenheim 2014-08-28 18:15:56
"151900920 la" Vérification " de code arrive deux fois . Une fois pendant compilation (la compilation échoue si le code a des défauts, des menaces) et de nouveau après la classe est chargée dans la mémoire pendant l'exécution (vérification byte-code réelle se produit ici). Oui, cela se produit avec le processus de chargement des classes (par les chargeurs de classe) , mais les chargeurs de classe eux-mêmes peuvent ne pas agir comme verifier. C'est L'ECM (ou plutôt le vérificateur présent dans l'ECM) qui effectue la vérification.

2
répondu TheLostMind 2014-08-29 05:22:33